Announcing Raven: Scientific Computing for OCaml (Alpha Release)

I’m excited to announce the alpha release of Raven, a modern scientific computing ecosystem for OCaml.

What is Raven?

Raven is a collection of libraries and tools for numerical computing and machine learning, including:

  • Nx: Multi-dimensional arrays with NumPy-like operations and pluggable backends (now pure OCaml, C FFI, Metal, next CUDA, WebGPU, etc.) - our equivalent of NumPy
  • Rune: Automatic differentiation and device placement, building toward JIT compilation - our equivalent of Jax
  • Kaun: Deep learning framework inspired by Flax/PyTorch, built on Rune
  • Sowilo: Computer vision library with differentiable operations, build on Rune
  • Hugin: Plotting library for data visualization - our equivalent of matplotlib
  • Quill: Markdown-first interactive notebooks - very different from Jupyter, but our answer to interactive notebooks

The ecosystem is designed to work together seamlessly, with Nx as the foundation, Rune providing differentiable computation, and domain-specific libraries building on top.

Getting Started

Install Raven via opam:

opam install raven

Here’s a quick example showcasing automatic differentiation with Rune:

open Rune

(* Define a simple neural network layer *)
let layer ~w ~b x = add (matmul x w) b

(* Compute mean squared error loss *)
let mse_loss ~w ~b x y =
  let pred = layer ~w ~b x in
  let diff = sub pred y in
  mean (mul diff diff)

let result =
  (* Choose device - Rune.ocaml, Rune.c, Rune.metal *)
  let dev = Rune.c in
  
  (* Initialize parameters on the device *)
  let w = randn dev float32 [| 3; 2 |] in
  let b = zeros dev float32 [| 2 |] in
  let x = randn dev float32 [| 10; 3 |] in
  let y = randn dev float32 [| 10; 2 |] in
  
  (* Compute loss and gradients *)
  let loss, grad_w = value_and_grad (fun w -> mse_loss ~w ~b x y) w in
  Printf.printf "Loss: %g\n" (unsafe_get [] loss);
  grad_w
val result : (float, Rune.float32_elt, [ `c ]) Rune.t =
  [[-1.74967, 0.863766],
   [-0.140407, -0.269364],
   [0.593187, 0.0197736]]
Loss: 2.13033

For more examples and detailed documentation, visit raven-ml.dev.

Why Raven?

Today’s machine learning ecosystem is converging on frameworks built atop ML compilers: high-level Python APIs that build computation graphs, then JIT compile them for performance.

In parallel, JAX and Flax have gained popularity with their functional APIs. For instance, JAX uses
function transformations (grad, jit, vmap) to implements its core features.

This is a landscape where OCaml has natural advantages. OCaml excels at building compilers, which includes ML compilers, and as a functional language, it’s a more natural fit for functional ML APIs than Python with JAX.

Given these technical advantages, Python’s dominance comes down to developer experience: the massive ecosystem and excellent prototyping ergonomics. We believe that with the right tooling, OCaml can match Python’s productivity for prototyping and exploratory work. And the ecosystem gap doesn’t have any fundamental challenge: we “just” need to write a lot of code.

If Raven succeeds, we believe it will offer a much more compelling alternative to Python: a language that enables rapid prototyping while eliminating the gap between exploration and production. You’ll move from local development to production without switching languages, without separate teams, without maintaining two stacks.

Technical Highlights: Rune’s autodiff engine

One interesting aspect of Raven is Rune’s implementation of automatic differentiation using OCaml’s effects system. As far as we know, this is the first production-scale autodiff engine built on effects, drawing on research by Jesse Sigal and earlier work by KC Sivaramakrishnan.

The architecture follows a modular design:

  • Pluggable backends in Nx allow implementation for different hardware
  • Rune implements an Nx backend that raises effects for all operations.
  • These effects are either caught by an effect handler (e.g. grad, jit), or, if unhandled, executed eagerly
  • This allows for composable effects handlers (e.g. grad (grad f), jit (grad f), etc.)

Technical Highlights: Quill Notebooks

Quill reimagines interactive notebooks with a Typora-like experience. Markdown renders live as you write, switching to raw markdown when you focus on a section for editing. This creates a natural writing experience where code blocks integrate naturally into your document.

The result is a distraction-free notebook environmnet, that prioritizes focused writing, while still providing full editor features within code blocks (coming soon ™!).

While still early, we’re excited to see how the community reacts to Quill when it is stable enough for daily use - we really think it has the potential to offer a much better notebook experience for teaching, reading, and other workflows.

Current Status

This is an alpha release. APIs are stabilizing but may still change. Things will break - this is expected at this stage! If you encounter bugs, please open an issue on GitHub; community feedback is invaluable to get to a stable release.

We’re currently focused on:

  • Stabilizing core APIs for the 1.0 release
  • Writing documentation and user guides
  • Supporting early users adoption (FFT, linear algebra, CUDA backend)

Post-Alpha priorities include JIT compilation and stable Quill environment.

Building a Community

One bet we’re taking with Raven is that it will allow a scientific and ML community in OCaml to flourish. As of now, it’s still largely a one-person project. While I’m committed to its development, we really need to see the development of a larger community for a project of this size
to survive.

If you’re interested in the project, the best thing you can do is to engage—whether by opening issues, reaching out, or contributing. Alongside reaching a first stable release, building a community is Raven’s main priority from now on, so any kind of contribution or engagement will be deeply appreciated. If there’s anything I can do to make Raven more welcoming and approachable, let
me know.

I’ve always believed that the best way to grow OCaml adoption is to provide killer apps for specific use cases (just like Rails did for Ruby). Raven’s not quite there yet in terms of advantages over Python, but it can get there, and if that’s something you’d like to contribute to, please reach out!

Getting Involved

Here are immediate ways to contribute as we work toward a stable release:

For users:

  • Try the libraries with your workflows and report issues
  • Share feedback on API design and usability
  • Help test on different platforms and configurations

For contributors:

  • Optimize eager execution backends while we build JIT compilation
  • Add missing NumPy/Jax/Flax operations to Nx/Rune/Kaun
  • Contribute examples and documentation

Don’t hesitate to reach out if you’d like to be involved closely with the core development:

  • JIT compilation
  • Stabilize Quill (many bugs to fix!)
  • New libraries

Resources:

Acknowledgments

I’d like to thank our early contributors and testers who have helped shape Raven:

Special thanks to our GitHub sponsors for their support:

Your feedback, contributions and support have been invaluable in getting Raven to this alpha release - thank you!

Supporting Raven’s Development

As Raven grows, I’m looking for sustainable ways to continue dedicating time to the project. If you’re an industrial user interested in using Raven for your machine learning or scientific computing needs, I’d love to talk about how we can work together.

For individuals who want to support the project, I have a GitHub Sponsors page. Any contribution, no matter the size, is deeply appreciated and helps ensure Raven’s continued development.

42 Likes

Wow. This is incredibly impressive!

Looking through some of the different pieces, I’m impressed that you’ve captured all of numpy’s advantages, including proper support of views, which Owl doesn’t have. The gadt-based interface is also a lot easier than Owl’s.

4 Likes

You’ve just put OCaml back on the map for me! I can’t wait to try it. I hope very much that this will succeed. I think you have identified some keys for success

  1. Inviting documentation
  2. A believable claim for technical advantages over the mainstream
  3. An application where Raven is undeniably attractive
  4. A critical mass of active users to get a community going

I think doing 1-3 well helps a lot for 4. I’ll try my best to contribute.

PS. this point:

is the point that the Julia folks have been making all along. Having used Julia after OCaml, I find that it’s possible (but not painless) to get extremely performant Julia code, but building and refactoring larger programs is way nicer in OCaml, which has a much more principled design.
Although Julia has succeeded in building an active, deeply knowledgeable and helpful community for technical computing, in the ML space they appear to struggle for adoption against the big Python frameworks. But that’s ok.

3 Likes

Thank you!

I have written some thoughts on Owl at Introduction - raven.

I should write up a more thourough comparison at some point, but on the top of my head, here are some key differences:

  • Support for views as you said - most view operations are free, unless they produce an array that requires memory re-ordering.

  • Support for GPU and other backends - the Nx backends are also relatively small (inspired by tinygrad), so implementing new backends should be a weekend project in most cases.

  • Flat API - a huge win in ergonomics in my opinion: the API should be very similar to NumPy (in both Nx and Rune), while leveraging the type system where we can.

  • Effect-based backend in Rune - a technical detail, but this is turning out to be a very elegant design: most core features (autodiff, jit, debuging, and soon automatic vectorizing) are all implemented as self-contained, simple effect handler. I can imagine that other key features can be implemented similarly without requiring massive refactoring.

  • Modular core - as mentionned in the announcement, one bet I’m taking with Raven is that it will give the push needed to allow an ML community to grow in OCaml. I’ve tried by best to find the abstraction sweetspot to allow the community to re-use pieces of Raven without depending on the the whole project. For instance, Nx can be seen as merely a small layer atop Bigarray, providing views and a complete set of numerical operations.

9 Likes

Thrilled to hear it, please don’t hesitate to leave feedback here or on GitHub when you give it a try!

1 Like

I think that’s an excellent idea. For someone only interested in array numerics, how does Nx compare to Lacaml?

Very bad in terms of performance!

Nx uses the pure OCaml backend by default, which is probably about 10x slower than what you’d get with BLAS.

You can use the C backend though:

module Nx = Nx_core.Make_frontend (Nx_c)

Which should be roughly equivalent (and if you notice performance differences, please report it!)

We’ll see how thing evolve and how the community wants to use the different libraries, but to start I’d recommend using Rune and not Nx if you need good performance, you can select your backend easily, and we support Metal and soon CUDA:

open Rune

(* With the C backend *)
let a = Rune.create Rune.c Float32 [| 2 |] [| 1.; 2. |] in
let b = Rune.create Rune.c  Float32 [| 2; 3 |] [| 3.; 4.; 5.; 6.; 7.; 8. |] in
Rune.matmul a b

(* With the Metal backend *)
let a = Rune.create Rune.metal Float32 [| 2 |] [| 1.; 2. |] in
let b = Rune.create Rune.metal Float32 [| 2; 3 |] [| 3.; 4.; 5.; 6.; 7.; 8. |] in
Rune.matmul a b
5 Likes

That’s a great read, and really nails the pros and cons of Owl and how you’ve addressed them.

This is both intriguing (because I have no experience in effects) and a little scary (because of the untyped effect issue) to me. I’d love to hear more about it. I’ll try to poke into this area of the codebase.

Definitely. I still need to try running it myself, but from my perspective this should be the new OCaml numpy.

To me this seems like the wrong default. An OCaml backend is relevant to someone who specifically wants to run in the browser. Any other user will want performance, and that should be available right away, just like in numpy.

How the heck did you write so much in-depth technical code so fast? How long did it take you? Also, I’d be super excited to join the effort.

2 Likes

I’ve been working on it full time for about 6 months. I started it at Recurse Center in February and continued after that.

I’ve been using AI extensively both to learn what I needed and to write code. I do feel that this is a key part of how I was able to write so much code (or at the very least a motivating factor for starting such a large project alone) - although from recent conversations I know I’m not the only one having a nagging feeling that sometimes this is just an impression. We need more research on the impact of AI on developer productivity!

4 Likes

Hello @tmattio,

Thanks for sharing the alpha version of Raven! I came across the project on GitHub a few weeks ago and found your approach quite interesting. I’ve actually been waiting to find some free time to explore it more deeply.

One of my initial questions was about its performance in linear algebra at this early stage. As far as I know, libraries like NumPy and SciPy rely heavily on optimized C/Fortran backends—primarily BLAS and LAPACK—to achieve competitive performance. Julia and R also use OpenBLAS and LAPACK under the hood for similar reasons.

From what I’ve seen, Owl adopts a comparable strategy, which helps explain why it performs well relative to tools like NumPy and Julia. In my own quick (non-general) evaluation here, I noticed a significant performance drop when bypassing those libraries—so leveraging them seems to be key.

I saw that you’re using nx_c_stubs, which I really like. I’m curious—are there any plans to integrate OpenBLAS or LAPACK in the future?

Also, it seems the current focus is on replicating NumPy and Matplotlib functionality, which makes sense at this stage. However, I’m also wondering about the long-term vision—specifically regarding SciPy and similar frameworks. I understand it might be too early to introduce such a large set of features, but is broader scientific computing support something that’s on the roadmap, or at least considered as a desirable goal down the line?

In summary, I think it’s a good idea to take an approach that shares the view that NumPy has been key to the development of such a broad ecosystem in Python, and that it has now become a standard.

PD: I like Hugin (the plotting system) is quite refreshing.

3 Likes

That’s a great comparison (I saved it here), but the big question in my mind is, do OpenBLAS and LAPACK really provide that much of an edge, or is their performance mostly matched if one uses SIMD? The Raven C backend can use SIMD - I’m not sure if it does right now, but either way, it can be done. While OpenBLAS and LAPACK have hand-tuned assembly, it’s not immediately clear to me that this is the only way to go - it’s possible that once one is leveraging SIMD, the added benefit of hand-written assembly is marginal. This needs to be benchmarked.

This is also why I think the Raven C backend has to be the default - people will be greatly disappointed by the native backend’s performance.

2 Likes

According to “someone sounding reasonably knowledgeable on the internet” they do if you need largish matrix-matrix operations.

1 Like

I was wondering about a comparison to OCANNL, which is also being actively developed. Is there a chance for synergy?

1 Like

I’m not an expert in this topic, but, yes, I suspect that part of the performance gains are indeed due to SIMD. However, there also seem to be additional optimizations involved — for example, as mentioned in the OpenBLAS FAQ, improvements may relate to better cache management.

The BLIS project, which aims to offer a cleaner and more modular BLAS-kind implementation (both in terms of performance and API), includes a more detailed discussion. They also provide performance plots. While different libraries tend to perform similarly on large matrices (asymptotically), that’s not always the case.

I’ve also added a PDF to my reading list that covers this topic in more depth — hopefully I’ll find time to read it someday!

First of all I am incredibly impressed. This is an amazing use of OCaml, and I cannot wait to see what you do next. I just wished I had a use case for it myself so I could play with it!

If I may address an elephant in the room away from technical considerations: you have been working on this full time for 6 months (and quite frankly, doing that much in 6 months is really impressive, congratulations). That being said, do you have a plan for sustainability of the project? How do you plan on bringing in money that allows you to keep working on this long term?

1 Like

OCANNL and Raven are very similar in design scope and goals, but significantly diverge in design decisions.

Raven is more mature, in particular OCANNL will be at version 0.6 by the end of the month and there are milestones for v0.7, v0.8, v0.9, which coincidentally will be followed by v1.0. Based on an outside view (i.e. how it looks like historically rather than how it feels like in the moment), ceteris paribus I expect to release v1.0 around a year from now. Part of it is that Thibaut is a “10x developer” and part is that OCANNL is “finding its own identity” regarding design in sometimes-foolish ways.

Both OCANNL and Raven are full-stack frameworks / library packs (two packages in case of OCANNL, multiple for Raven), i.e. they offer implementations for both front-end, and for back-ends. With sufficient additional work, they should be able to swap backends (in the sense of what does heavy-lifting behind a more-or-less thick wrapper). They can also more readily share individual pieces of technology. Note that on the spectrum eager->lazy->compiled, OCANNL is compiled – in OCANNL code is run explicitly (but there are various automations for ergonomics, e.g. host-device data movement).

Thanks for asking!

2 Likes

It initially used BLAS, but after getting some problems during the release, I removed the dependency.

Generally, Raven is aggresively aiming to have as little dependency as possible, so if we can do without a third-party dependency like BLAS, all the better.

As a side note, there’s really nothing magical about BLAS: good heuristics for parallelization, SIMD, and ASM where needed, all things that we can replicate for our use cases in Raven - we’ll just have to see if the added complexity continues to be justified as we add performance optimizations.

That said, another important consideration is that our answer to performance requirements in Raven is JIT compilation, not the eager Nx backends. We should have good enough performance in the eager backends that local development is pleasant, but my guess is that if you’re at a point where you need more than native C performances, our answers will be “use JIT” - which will perform optimizations that an eager backend with CBLAS won’t be able to make, like kernel fusion.

So we’ll need to see how things evolve - Raven will be driven by community feedback - but I’d tend to think that, no, we won’t be re-introducing a dependency on CBLAS.

Absoludely. Our Ariadne’s thread is: everything that you can do in Python, you should be able to do with Raven, with the same productivity and ergonomics.

We don’t want to have a bloated API in Nx/Rune, so we’ll need to see if we want to have a new packages (Raven, as a monorepo and full ecosystem has an advantage in terms of offering a consistent set of packages with well-defined boundaries vs Python, we should utilize that!), but for now every function from SciPy should be a welcome addition. If the API is bloated and we need to factor things out, that’ll be a good problem to have.

2 Likes

Noted, thanks for the feedback! I think the only reason the OCaml backend is the default now, is the time I spent on it, and the pride I take from some of its optimizations (e.g. it has it’s own implementation of a parallel_for à la Domainslib that reduces allocations for performances), and so I didn’t want to have it being burried in favour of a less technically-impressive and impure C backend.

Not exactly a UX-driven reason, so making the C backend the default is sensible :slight_smile:

That said, another point in favour of the OCaml backend: it makes Nx very portable: you should be able to compile it to JavaScript, Wasm and Mirage for instance.

3 Likes

Thank you for the kind words!

I started thinking about it, and took some steps towards this, e.g. see Support Raven - raven.

That said, I didn’t imagine that an industrial user would be very interested in funding a project they wouldn’t be able to use. Now that we have an alpha out, it makes more sense for me to be more proactive to try to get funding for Raven.

I also want to thank the early sponsors of the project @daemonfire300 @gabyfle @sabine @avsm @zbaylin @fermin, and in particular Tarides, who recently made a very generous sponsorship. Every contribution helps, and I’m incredibly grateful for the enthusiasm and the support from the community.

Stepping back, I have other projects that build on Raven that I’d like to get off the ground, and if they materialize, they would be a good way to fund Raven by proxy. I’ll be sharing more soon hopefully, but I imagine the dots are not too hard to connect with my work on OCaml MCP and Mosaic :wink:

Short answer: I don’t have a concrete plan yet, I’m working on it, the best way to support the project financially is through GitHub sponsorship. If you’re an industrial user interested in using Raven, please do reach out! And if you’re interested in AI tooling with OCaml, I’d love to talk.

2 Likes