Hopefully, at the end of it, using Rust as a training backend and deployment platform will not look as crazy or confusing as it sounds. There will be many pitfalls along the way and most of the techniques you end up trying will not work out of the box, hence the focus on fast prototyping and iterative improvements.
Ease of use alone will not take you far though: training ML models requires a fair amount of heavy number crunching and Python is definitely not the fastest language out there. Python is the frontend of these systems, the user interface that makes it easy to stitch things together.
Indeed, this the often overlooked feature of Python: it is reasonably easy to interoperate with other programming languages using its Foreign F unction I interface (FFI). The sociological elements are crucial to the success (or demise) of most projects, even if some people find it hard to swallow.
), its penetration level in academic institutions was non-negligible as well as the fact that most of its scientific ecosystem was already established when Deep Learning conquered the spotlight. We have briefly run through some characteristics that enshrined Python as the preferred programming language for ML development.
The world does not stay still though: changes to the surrounding landscape can significantly shift the perception of which one is the “best tool for the job”. The microservice architecture currently dominates the design space: companies run their businesses as a loose collection of containerized services communicating with each other over the network.
If we are talking business, it's important to stress that ML models do not exist in a vacuum: they are part of a product or a process that a company wants to launch, optimize or improve. It is thus fairly naive to believe that a team composed exclusively of Data Scientists has a good shot at succeeding.
Take, for example, “systems-level” work that deals with low-level details of memory management, data representation, and concurrency. Traditionally, this realm of programming is seen as arcane, accessible only to a select few who have devoted the necessary years learning to avoid its infamous pitfalls.
Rust breaks down these barriers by eliminating the old pitfalls and providing a friendly, polished set of tools to help you along the way. Programmers who need to “dip down” into lower-level control can do so with Rust, without taking on the customary risk of crashes or security holes, and without having to learn the fine points of a fickle tool chain.
Going back to those trends I mentioned before, you can spot again the power that comes with being full stack: the same person who took care of the model exploration (in Python) can deep dive and optimize the final solution using Rust to rewrite its hot path. I prepared a workshop for Rustiest 2019 : we implemented from scratch K-Means clustering using array, a Rust equivalent of Bumpy.
I wrote some notes on the workshop a couple of weeks ago and the material can be found on GitHub : it's structured as a series of test-driven exercises, with each step contributing to the final solution. As you can see from the source code, the focus is on clarity rather than obscure optimizations: it's a textbook implementation of Lloyd's' algorithm.
Linfa on a Rust web server has also the lowest error rate under heavy load. It's too small of an experiment to draw drastic conclusion, and I am sure you can find faster implementations of Lloyd's' algorithm for K-Means out there.
Everybody could have written that Rust implementation with a bit of training in how array works (try the workshop material!) As I briefly mentioned before, linfa-clustering is a subset of Linda, a general ML framework in Rust that I plan to focus on in 2020.
(I don’t hate programming memes, it’s just that rarely funny, and they’re very repetitive). All these are reasons that low-level languages are not good for machine learning.
In GC, objects in the heap that are no longer used by the program are invalidated by the collector. GC strategies are not perfect, and data requires to be stored in massive objects which occupy a large set of memory addresses in the heap.
These invariant types prevent the objects in heap from racing each other in concurrent systems as it prohibits concurrent reads and writes to a single memory location. But in tandem with ownership rules, we get total memory safety.
When we want to use a variable outside its scope, we either have to copy, move or borrow it. We should use Rust ’s unique syntax to come up with new patterns, new ways of doing things.
Rust ’s ability to micro-manage the memory with a high-level interface, and its superb concurrency libraries, makes it an awesome tool for ML. So your fear of “modicum I hate static typing!” will vanish in a second.
Since I want to make a series of ML in Rust posts, what I’m going to do is explaining Rust ’s basic features in a cons ice manner. Type safety is the extent to which a programming languages prevents type errors.
To explain the scoping, get an online Rust compiler and run this code: We saw that, like Kotlin, Rust blurs the lines between static and dynamic typing.
Bool char signed integers: i8, i16, i32, i64 unsigned integers: u8 etc floats: f32 and f64 array, a fixed-size segment of memory slice: a dynamically sized view into a continuous sequence STR: string slices type: a finite heterogeneous sequence The value after colon denotes the input parameter type.
Notice that we didn’t add a semicolon when we wanted to return x to the power of two. Any expression at the end of a function’s block denotes its return value.
We explained reference at the beginning, and borrowing as one of the ways to transfer ownership. However, STR s should be used as function parameters because they are immutable and can only be accessed by referring and borrowing which are similar operations.
Str s can live in the stack, the heap, or any other place in the memory. Ends are an interesting way to create a type that will hold of the values of few different variants.