From Python to Elixir Machine Learning
thestackcanary.comSomething not mentioned is Explorer (https://hexdocs.pm/explorer/Explorer.html) which is a very nice dataframe library backed by Rusts Polars https://www.pola.rs/ with great integrations for Livebook https://livebook.dev/.
I found explorer quite frustrating. I've used polars in python and loved it, but I brought in some financial data and couldn't strip off "£" from the start of a string so I could go on to cast it to a number.
As far as I could tell I would have to bring that data into elixir, do the text processing and put it back into explorer, which to me defeated the whole point of a dataframe library.
I imagine it's good for precleaned data, using it with the built in datasets has been fine
José from the Nx/Explorer team here.
Feel free to open up an issue! We have been focused more on high-level features (such as integration with S3, Postgres, Snowflake, SQLite, etc) and therefore we are missing many functions that already exist on Polars. Good news is that it is very quick to add them, so just let us know. :)
Thanks José!
Yeah I noticed that, it looks like the numeric manipulations are well represented, less so for strings.
I'll dig out the the code later on and get an issue raised.
Seems that for that case you would need to use `mutate_with`, which as you say does pass data between systems.
My understanding is you can use any Series operations without penalty (ie. they get passed into some rust NIF call), https://hexdocs.pm/explorer/Explorer.Series.html#functions-s..., which does include whitespace trimming, but not arbitrary strings, but I imagine it wouldn't be too much of a jump to add arbitrary constant strings. Might just need to expose `str.slice` or `str.replace`.
The docs do imply that `mutate_with` operates lazily, so you only pay the transfer cost once per row, no matter how many mutations you're applying, but whether that's performant enough depends would be case by case.
mutate_with is still lazy and therefore you can't transform it. If you need to use transform, then you need to do:
which _is annoying_ since you are not supposed to use it. The correct way is to extend the Series API, which we will be very happy to!new_column = Series.transform(df["column"], fn arg -> ... end) DF.put(df, "column", new_column)
You can use str.slice or str.extract to clean the data:
https://pola-rs.github.io/polars/py-polars/html/reference/ex...
Yes for polars in python. This was an issue I had with explorer in elixir. There is no elixir binding to the str.slice or str.extract functions yet
Don't miss the interesting book (which I just bought) in beta here:
https://pragprog.com/titles/smelixir/machine-learning-in-eli...
Recommendation seconded. I'm only to chapter three due to time constraints, but it is well written and approachable for someone lacking ML experience.
I use Elixir for a long time and wouldn't recommend it for ML over Python. Yes, maybe Elixir has some advantages and solutions for pain points because of VM architecture and other subjective reasons but doesn't come close to what Python offers in terms of tooling, support, community. Also, if you juggle more complex data in Elixir, it's something that you need to get used to coming from Python, it will be much much different and therefore harder to grok for someone not used to the style.
You can always make Elixir app talk to Python ML backend and get the best of both worlds if you desire.
Nx solves all of the issues you're citing. That is how you do ML in Elixir
Have you used Numerical Elixir (Nx)?
I can no longer edit parent post so to further elaborate on tooling: even if Elixir was comparable to Python (let's assume it's true as of today), there is a lot going on in AI, so that won't necessarily be true tomorrow. There is no doubt Elixir will always be slower to catch up to recent development because of smaller community. This also applies to how quickly issues will be resolved as they appear. It's likely OK if you're toying with a hobby ML project on your own, but not something you'd want in a startup with stakeholders who have expectations in regards to timeline, and so on...
I like Elixir for web development otherwise, it is a much more stable domain so above doesn't apply (although I've seen some claim otherwise, which is telling how much more of an issue it would be for niche ML use case).
I'd be very happy to be proven wrong by some case studies of how companies leveraged Elixir in real ML projects and concluded it is superior to Python.
If that reasoning would hold true then there would never be a new best/most popular language for a specific domain, but there are many counter examples.
And just as Elixir is (in my opinion) preferable to Python for web development, it's possible that the same may happen with AI.
I agree that it's a better choice for web development purely from technical standpoint (so ignoring things like smaller market for devs), but I'm biased towards it.
And yes, when it comes to AI, things also could change in favour of Elixir - I would be pretty happy about it.
your reasoning is basically "it's not popular enough"
your flaw of reasoning can be trivially pointed out simply by explaining that once upon a time, Python was NOT "the language for machine learning". Essentially, NO "X is the solution for Y" started out that way. Which is why appeals to popularity are a fallacy.
So you wouldn’t recommend it because it’s different than Python?
What ML tooling is better in Python?
I wish there wouldn’t be such a song and dance about “moving away from Python”. There’s nothing wrong with creating ML tools in Elixir, but it’s always Python is slow, Python has no concurrency support, blah blah
I come from Ruby but the reactions can be similar, happy to give my data point.
The thing is Elixir is really good at an increasing number of things.
If you need to write a HTTP proxy in the middle of your application, since Elixir processes & incoming HTTP workers are cheap, you do not need to go evented: it just works.
If you need to have reactive web apps with automated changes pushed to the client, it's the same: there is no need to external tools (e.g. any cable) at certain scale.
If you need to do some scripting, there is `Mix.install/2` for single-file dependencies description & use.
If you start crawling too much web pages or process to many APIs, the concurrency support kicks in and there is less need to scale (or later), turning into fewer machines, fewer ops problems (or delayed) etc.
And now you start being able to use MachineLearning, deploy the same type of code on GPU, embed Machine Learning models right in the middle of your web app without much work, etc, which in turns makes it a nice platform for apps / SaaS.
Elixir really is becoming a Swiss-army knife which scales easily :-)
And nerves makes it easy to do IoT stuff / almost-embedded
add rustler and you can even do some systems stuff! (We use it at work)
still not easy at the most important thing of all: being approachable, instrumented and intuitive to people less dedicated to programming.
I say this as someone that likes elixir, but after seeing it failing miserably at my org, I'm very skeptical it can be thrown around like a spring or node or django project. It needs real support from the org and requires module design skills that are not present in most random devs from a random org.
Could you expand on what you mean by this?
Module design doesn't seem any harder than class design in JS or Python.
Do you mean the language is generally harder for non-developers? Or that Elixir is harder for JS/Python developers to pick up and write good code? Or something else?
Writing well designed Elixir code does seem to require a fairly different approach from most common OO languages, at least at a surface level. (Although IMO that's more because you can copy OO patterns you've seen before without thinking much about why they're good patterns than because good design in Elixir is much different from OO)
sure thing! I'll try to make points related to what I observed and experienced in my org, starting with one huge huge huge preamble which is: I work in an average org with average joe devs. an average joe dev to me is someone who "just wants a job" and is not very interested in furthering its own professional development or learning new things unless trained & forced by the job. it's perfectly fine to be an average dev, I understand I'm sounding like a snub but the difference is real, exists, it's tangible as I touch it every day.
having said that, designing a proper elixir module (which basically is a bunch of functions that operates on a certain data structure usually represented by map of a certain shape) carries a certain level of fundamental understanding of the operation you're doing, which in my experience is one of the hardest things to get correctly.
It also requires a different way of exploring code as you can't do the familiar `.` and see what happens, you can't just do `price.toCentsValue` but need to do `price |> Price.toCentsValue` and so you need to know the existence of the `Price` module, which might not exist and be buried in `Cart` or as an helper in some controller because you did not understand clearly the domain and the modules responsibilities. Attaching behaviour to data is powerful, explorable, and most people are used to it, even if it's the wrong place in principle, with modules this is flipped, it's now data that must thread through operations, and it's not super easy to grasp.
Also, tooling is not that good (dialyzer sucks, intellij plugin not that good, vscode lsp good but still not a proper experience from people coming from c#/java, type annotations are not that readable...), pattern matching and destructuring on fn arguments confuses people and it's not super easy to read, and a million other papercuts related to tooling and syntax.
We don't have many elixir codebases (let's say around 15-25%) and I've seen incessant whining about "we don't want to maintain elixir" simply because the majority of people cannot be bothered to learn another mountain of quirks and papercuts (every lang has them) plus also losing the familiar way of working they already have, and having to remember that for the spot ticket that appears once in a blue moon on jira for elixir. That's why I think elixir needs extra support from the organization, basically in mandating it to be the primary language, teaching people proper design + proper code navigation and structure techniques, etc.
I hope I've been clear in my long winded ramblings; and I still wish a great future for elixir, so it becomes more approachable in average places like mine
> It also requires a different way of exploring code as you can't do the familiar `.` and see what happens, you can't just do `price.toCentsValue` but need to do `price |> Price.toCentsValue` and so you need to know the existence of the `Price` module, which might not exist and be buried in `Cart` or as an helper in some controller because you did not understand clearly the domain and the modules responsibilities. Attaching behaviour to data is powerful, explorable, and most people are used to it, even if it's the wrong place in principle, with modules this is flipped, it's now data that must thread through operations, and it's not super easy to grasp.
Not sure, I think you're picking and choosing things to ramble about. While you can't just do `price.toCentsValue`, and have to call `Price` module, in a OO language, you would need to instantiate `price = new Price(amount 10)` or something before calling `toCentsValue`. This means you're aware of the Price class, same as being aware of the Price module. If anything being aware of the module infact is better IMO since it allows you trace through explicitly what the code is going to do. Your point is correct if you're working through macros though.
I'm not really picking anything, just sharing how it went with elixir in my org. I'm sure we could have done better, but the pit of success was not there for the polyglot teams. the elixir-only teams did a bit better, but mostly they just learned the ecosystem and then GTFO'ed out to greener pastures since they just wanted to write elixir and only elixir.
about your specific counterpoint, I think it's partially valid; I don't instantiate modules, I might not have named structs but just operate on Maps so I don't know the supposed module name, I might have misplaced the function in another module (while it's very intuitive to stick it to the object in oop)...and a million other things that are way too different for the average joe.
Thanks for sharing!
We could certainly debate the objective merits of Elixir vs other languages (which seems to be the primary discourse in this thread and elsewhere) but hearing subjective developer experiences is also critical.
It doesn't matter if Elixir is objectively better or not, if lots of devs who are exposed to it are having a hard time it's worth asking why.
In addition to developers not wanting to expend additional effort to learn a new language or paradigm, I believe there are gaps in the ecosystem especially around medium-advanced topics.
I'd be interested to hear what some of those gaps are from your perspective, as they represent opportunities for community creators.
In other words, what resources do you wish existed?
The org I work at has the same issue with Elm, there is one Elm product and no one really wants to take those tickets because everyone hates dealing with it. It has become a total pain in the ass, and I believe someone is rewriting the app in React
I'm guessing the people who actually love Elm left.
You really do have to love a paradigm to work with it, because paradigm shifts have a cost. Elm's paradigm shift is "do everything declaratively/immutably/non-side-effecty" and the massive (IMHO) benefit of going about things that way is "no runtime errors" (!!!) in addition to quite performant code.
But yes, the cost is there, and it is that you sometimes just want a side-effect to get something done, you sometimes just want to call into another library to get something done, etc.
The thing is, if Elm allowed this, or made it easier, you'd lose the Elm guarantee of "no runtime errors". Which, frankly, is a pretty big one- just inspect any popular domain's web page and you're likely to see dozens of JS errors that are simply hidden from most users, contributing to a "janky" web experience.
I literally just inspected this very page I'm typing this comment on and I see:
The cost of perfection is high. You really have to love the ideal.This page is in Quirks Mode. Page layout may be impacted. For Standards Mode use “<!DOCTYPE html>”. Error: Promised response from onMessage listener went out of scopeBut yes, if no one does, then Elm is a boondoggle.
I'm dealing with something similar with NixOS. NixOS's big guarantee (which is also big) is basically "no build or runtime failures that are due to misconfigured dependencies". But there's a steep learning curve and scattered documentation. The core idea is amazing, though, and that's what I love. The rest I tolerate while climbing the mountain.
That's going to be the case with almost any legacy project though
> I work in an average org with average joe devs. an average joe dev to me is someone who "just wants a job" and is not very interested in furthering its own professional development or learning new things unless trained & forced by the job
so basically you're all doing things you hate, which is literally the worst possible work environment, and you're trying to use this as a data point for why Elixir "isn't for average coders". I have news for you, dude, you're not even at the "average coders" level, you just work in a "code mill", I'm guessing India.
you have an absolutely skewed perception of average in our field. I'm guessing "less than 3 years of experience".
nevermind the random stab, it's just to make you understand how random some answers are. in any case, no one is trying to touch your precious language, if you can't understand the context in which elixir failed (hot startup that HAD to hire everyone and its dog in 3 months + polyglot environment), not my problem
your last paragraph largely answers your questions.
it doesn’t take much to yeet some python scripts (and more) at the wall and get something to stick. SO, GPT, pick your poison, it’s painfully easy. solved problems as far as the eye can see, with a little glue or tape to hold it together.
elixir demands more of an investment. more than approximately zero is quite a bit if you already have momentum.
(elixir can absolutely be yeeted. not arguing otherwise.)
Honestly long run elixir code by LLMs is going to be better because the llm won't have enough attention or context to be sure that mutable passes to functions don't absolutely wreck your data
On the other hand, it may filter less dedicated people from showing up at your door.
this has been a point of contention with numerous hr departments that needs to hire fast "cuz investors!!11". this is the reality of life sadly
This is the real problem.
Most orgs that fail on elixir fail due to management.
absolutely, that's what I said when I talked about strong org support.
also, if you don't have strong org support, you risk getting onboard people that just want to work with that specific technology that WILL gtfo as soon as they need to change team to one that doesn't use it, or if the technology is sunset, etc., so it's even more risky to have an exotic stack in the middle of more common stacks
This is a problem, that needs to be fixed in tech management. Tech managers need to trust their dev talent. It's like a self fulfilling prophecy.
Elixir is risky, so let's move off of it ==> devs leave. Elixir seems risky.
And then the devs/ecosystem gets blamed.
Also a risk of polyglot environments. You can easily end up with teams that lack deep knowledge of the languages and libraries you're using.
I do agree with the need to make it more approachable indeed.
It is too much a "language of experts" at the moment, although it is not caused by the language itself, more by the topics covered in general.
"Everything is working fantastically with our python ML project but we're rewriting it in Elixir anyway" would be a weird article wouldn't it?
This article in particular doesn't feel like there's any song and dance. The very first line is directed at people already using Elixir who are looking to stay in Elixir-land while getting deeper into ML.
Those are real issues though.
Is concurrency useful for ML?
If your data loading pipeline grows even slightly complex, then yes, you absolutely need concurrency in order to deliver your samples to the GPU fast enough.
The current workarounds to make this happen in python are quite ugly imho, e.g. Pytorch spawns multiple python processes and then pushes data between the processes through shared memory, which incurs quite some overhead. Tensorflow on the other hand requires you to stick to their Tensor-dsl so that it can run within their graph engine. If native concurrency were a thing, data loading would be much more straightforward to implement without such hacks.
Yes, it can be.
1. Loading data
2. Running algorithms that benefit from shared memory
3. Serving the model (if it's not being output to some portable format)
There are also general benefits of using one language across a project. Because Python is weak on these things, we end up using multiple languages.
You end up having to do a lot of things in a ML training run, some of which you can do in parallel because it’s not important now (eg saving metadata) or because you’d otherwise be resource limited (eg loading data and formatting batches for training)
And for this you cannot use Python's multiprocessing because ... ? Sure, moving data between processes is slow because of pickling [0]. However, I'm using parallel processing for the things you suggested, and for these it works great.
If I really had the use case and needed threads, I'd much rather use C++ bindings in a Python package than rebuilding the whole thing. Guess it depends on the scale we are talking about.
[0] https://pythonspeed.com/articles/faster-multiprocessing-pick...
It’s handling all the things that can go wrong when communicating and coordinating across processes, across machines, or troubleshooting bottlenecks on running systems that Elixir (and Erlang) excels.
Concurrency generally makes things run faster. If you test your ML methods your tests will complete faster if the ML methods are able to use and take advantage of concurrency. Some people consider that useful.
No, parallelism is useful, concurrency without parallelism is not useful.
Go and elixir provide some parallelism but the primary focus for both languages is concurrency.
It's not. Until you need to deploy it.
yes but generally they are not that kind make or break type issues like eg Julia correctness problems.
Correctness problems? Could you expand on that? Not doubting, just curious. Thnx
Python is slow and concurrency is not great.
lots of negativity in here from people who have invested a lot of effort learning python, despite that there's also people who complain a lot about ML/DS in python. Is it an expression of sunk cost fallacy? If you don't support people who are trying to make a difference, nothing will change.
It's a weird mental block too - learning a language like Elixir, being so well designed and documented, is as comfortable as it gets.
Devs we hire without direct Elixir experience pick it up really quick (within a couple weeks). The energy needed to "get good" with Elixir is really not much considering it provides veritable super powers on the backend and introduces a whole category of concurrency concepts that are not easy to grasp elsewhere.
specifically over python, immutability in function passing is amazing for beginners and dealing with beginners.
How confident are you that the junior you just hired is operating correctly in the other_code module they're responsible for
import other_code, as: other def f: my_dict = {"foo": 1, "bar": 2} other.function(my_dict) return my_dict["foo"] # ==> you might be wrong about what's in my_dictDo you know which resources your devs are using to learn Elixir from scratch?
* Elixir-lang Intro: https://elixir-lang.org/getting-started/introduction.html
* Exercism track: https://exercism.org/tracks/elixir
* Sasa Juric's book: https://www.manning.com/books/elixir-in-action-third-edition
* Dave Thomas's Elixir Course: https://codestool.coding-gnome.com/courses/elixir-for-progra...
* Phoenix Guides: https://hexdocs.pm/phoenix/overview.html
* Ecto Guides: https://hexdocs.pm/ecto/getting-started.html
The above covers the language basics/ideas/concepts and the main tooling (Phoenix/Ecto) if you're looking to build apps or get an Elixir job. I definitely recommend the Phoenix Guides or similar - they're very high quality and kept up to date with any new releases or changes while books can sometimes get out of date.
Perfect, thank you a ton.
Show me I can save a considerable amount of time training a 70b parameter huggingface model by switching to Elixir, then we can talk about me learning a new language.
The training costs and performance at that scale are mostly driven by hardware and I personally don't think language will make a large difference (I may be wrong).
Most of the Elixir Nx efforts are on inference, especially on how you can embed and scale it using concurrent and distributed patterns (see this post/video [1]). It may not be what you are looking for but we have more folks deploying than training models, so maybe they will find incentives to give Elixir a try. :)
[1]: https://news.livebook.dev/distributed2-machine-learning-note...
Seems like you didn't read even the first line as this article is directed at people already using Elixir who are currently doing ML stuff with Python.
I did actually read most of the article. Did you read the section immediately after that?
> Why is Python not Sufficient?
It then proceeds to make a case why Python would not have enough speed or support for parallel processing, which is what I'm disputing.
Instead of moving to Elixir I believe it makes more sense to wait/move to Mojo when it's ready:
Elixir (NX) is ready now, Mojo might be, at some time in the future.... also Mojo won't have the BEAM or ergonomics around Functional Programming.
ML is not an island, it is part of a much broader "data science" universe that is currently served fairly well (still imperfectly) by the Python/C++ stack and is not easy to replicate.
Throwing BEAM or FP acronyms around won't really strike a chord with people working with data and models.
Mojo will (as per promise) tap into the wider ecosystem. Other platforms are more than welcome to try but this ultimately requires a huge community of scientists / developers to become a real alternative.
There are very real limitations to the tooling approach summarized as "slightly more ergonomic APIs to underlying C/C++ code" that is currently dominant in Python qua ML. One of the biggest is of course extensibility, which, if difficult enough (as is the case in most Python ML tools unless you're extending only at the relatively slow Python layer) drastically hinders progress in making tooling better while keeping performance good.
Other languages have certain features that make extension and integration feel like first-class concerns which lowers the barrier to contributions from a wider range of people and also helps keep e.g. dependencies and build processes relatively simple.
I would not necessarily disagree with any of these points, just sceptical that these are enough to create the substantial investment by diverse actors to create real alternatives. The example of Julia non-adoption is very important to keep in mind.
Python was not designed for ML, it happened to it, the way Android happened to Java etc. Loosely speaking the Mojo project serves a function similar to that of Kotlin in the Android mobile world. Trying to remedy some recognized friction points while maintaining the benefits of a widely established ecosystem.
Obviously not holding a crystal ball: if the ML hype mutates into something more permanent and very widely embedded across different verticals (not just the big tech sponsored pytorch / tensorflow platforms and use cases) and if the Python/C++ combo becomes a recognized bottleneck then the conditions might spark another approach.
Python syntax has really good ergonomics around functional programming. I hardly write loops when I use the language now.
Mojo is pretty cool but its a difficult road to take - especially to implement the breadth of accrued functionality of a 20 year old language like Python.
Elixir & Python are not an apples to apples comparison - there are fundamental differences in the programming model (functional, immutability, etc) and runtime (preemptive scheduling + OTP) that is the reason it has distinct advantages not available without heavy cost trade-offs elsewhere.
Either way once Mojo is production ready Elixir will be able to use it as well like it does Rust, Zig, or Python.
Given how Swift for Tensorflow went, how openai was equally pushing for it, I would rather take a "wait and see" approach to Mojo.
Do you mean OpenAI or do you maybe mean Fast.ai?
It might have been fast.ai, not sure.
Since it aims to be transparently compatible with python Mojo will very likely suffer from the worst part of python: packaging
Last week heard a story about an ML dev that would literally rebuild his system every week because python would break it
No source code, no thanks.
At first I thought what does Nx (nrwl/nx) has to do with machine learning, then I figured context is about Elixir lib named Nx.
Naming things is hard.
Agreed, naming things is hard. That and off by one errors are the three hardest things in software development, IMO.
I just ran a 2006 Java code to detect and read car license plate, and it ran in the first run on Java 17. The code is 17 years old and runs just fine without any issues. I think Java folks messed up AI/ML space due to licensing. But I still think it's best PL for AI/ML.
What makes it the best language for AI and ML? I've never heard that take so just curious your thoughts. It's nice that legacy code still runs but that's usually not people's concern in ML.
I (and my colleagues) have worked on statistical, data analysis, and ML in Java since before data science was even a career field, and before Python became popular. In my opinion Java has better IDE support, more stable and proven libraries, and high performance.
Java does occasionally require that a person might have to implement their own code after reading a research paper, but I've always enjoyed that part of the job.
I've never understood Python's popularity except that I've heard some people say that it's used at Google.
You would be happy in Elixir as well, the language is pretty much frozen and very small bug fixes and features are added.
It's definitely not a fast moving language.