Julia for Python
You have performance problems with your Python code but are sick of rewriting it in Cython/C/C++? Julia might just be the language to solve your problems. It's ease of use rivals that of Python, but it runs as fast as C. It has a powerful, optional type system, which is great for writing high level and generic code. In this talk I will walk you over some examples that show off Julia as a great language for writing math and complex libraries. I will also explain, how one can wrap their Julia packages in Python, to also reach the people that are not yet ready to leave Python for a new, hip language.
This session took place in track PyData and was classified suitable for expert domain / basic python by the speaker.
Transcript (auto)
Auto-generated from the recording utilizing Open-Source AI. Speaker labels (Speaker 1, Speaker 2) reflect diarization, not identity. Timestamps refer to the recording.
Speaker 1 [00:03]
I'm Simon Danisch. I work at Next Journal at the moment. I'm their Juya expert. I've been working with Juya for around six years in graphics, in GPU acceleration and on the plotting infrastructure. Today I will talk about what Juya is and when to use it. I will talk quite a bit about how to call other libraries. and a bit about the performance of Julia compared to other languages. I will talk a bit about how to write nice composable libraries in Julia and how it's unique in that regard. And I collected a few noteworthy examples to give you a taste of how Julia looks like. And I will finish with a little demo of how you can call Julia from Python and discuss a bit like the disadvantages of Julia. And this is all in NextJournal, the company I work at. So it's a notebook platform where you can run Julia and Python in the cloud. And it also has a presentation mode, which I will be using. Right. How does this work? Huh. Okay, so what is Julia? I usually describe it as Python at the speed of C with very elegant syntax for math, like from MATLAB. So you get all the dynamic features from Python and the interactivity at the speed of C. And I think it combines the advantages of these languages. It's also multipurpose like Python and multi-paradigm language so you can combine more functional approaches with more object oriented approaches it appeared in 2012 so it's pretty young compared to Python but it's also already pretty usable and mature and steadily growing then my favorite feature lists from Julia is that it inherited quite a a bit of goodies from Lisp like fully featured macros that you can treat code as a data structure so you can just manipulate it like any other data structure and e-valid and a lot of functional programming inheritance one of the most noteworthy features is multiple dispatch in Julia where you can compose multiple functions very nicely by not just dispatching on one argument but dispatching on the type of multiple arguments in your function I will talk a bit more about it later and I really enjoy the optional type system in Julia because it doesn't get in your way if you're just writing something but if you actually sit down and want to write a mature library it's really nice to have a fully features type system and she has a lot of instruction and reflection functions so you can look actually at what code Julia generates down to the assembly code you You can look where functions are defined. You can immediately get their source code and things like that and get help for function, which makes it very easy to get started with Julia. I tried to make a little graph about when to use Julia and where it's used. Here on this axis, I have the theoretically niceness of Julia's features in this area. And here I try to roughly estimate how many projects there are in Julia at this moment. And why I said theoretically nice is because the more projects there are in an area, the easier it will be to use and the less awkward. So if it's not theoretically, it would just be like a straight diagonal because if there's only one person using Julia, for example, for a hard real time, there won't be many libraries for it and it will be awkward. And this is kind of the case for machine learning, I think, in Julia, because Julia has very incredible features for machine learning. Because it's fast, it has very good GPU integration, but not many people use it for machine learning at the moment. So there are definitely libraries missing. The strong part is more in scientific computing. Julia was created for this and for optimization problems Julia has a long history in optimizations with jump which was a very successful library early on and it probably offers the state of the art for solving optimization problems and there are a lot of physics and simulation projects with finite element simulations and probably Julia gets its most money from big finance company doing finance modeling and nowadays there are quite a few climate modeling um projects in jewish julia so in this area here i can definitely say you should take a look at julia if you work in this if you go more into this area i'm like okay julia might be great for this but there are not as many mature libraries yet some people use julia in production with web servers but you won't have all the libraries there and some of them aren't very mature the same is true for desktop applications not all of them are nicely wrapped yet Qt there's a wrapper but it's not well maintained but there are desktop applications so it does work hard realtime is an interesting one because Julia is a garbage collected language which usually doesn't work as well with hard realtime but since you can fairly easily write Julia code without doing any allocations you can actually use it for hard real time but I think there's only one project that is actually doing that so there's not much data about it how nice it is actually in the end and here like in the bottom corner that's something that doesn't really work in Julia so if you're trying to target iOS Julia doesn't run on iOS I'm not sure when it will run on iOS on android actually like i think two weeks ago it started running on android but it's still in an early phase so there's not much to say about it if it will be nice and for really secure application where you probably want to prove that your program is bug free and things like that um julia isn't the right language it's not battle proved in this and yeah now Julia is very famous for its performance that's what it's known for so that's definitely one of the biggest use cases and you can see this nicely on the slide here it's a few micro benchmarks compared to other languages the baseline here is C and you can see that Julia really nicely is around the C performance and I think you can even go as far is that this variance around it, that you would get a similar variance between different C compiler versions. So it's usually very close. And in all my years comparing C and Julia performance, it was usually a bug if Julia didn't reach the same performance. Now, why is performance important? I hear a lot, there have been a lot of articles about like, yeah, I don't care. python is fast enough why should i think about this and my main reason for this is that i want to set on a language where i know that i don't have any barrier in the future because probably the moment where you run into a problem you have like a lot of deadlines and you want to really finish your project and suddenly you notice uh shit the performance doesn't work out it's unusable that's probably the worst moment where you want to switch languages so i try to set on a language where this won't happen it's relatively easy to write python code that runs as fast as c because it actually calls out to a lot of underlying c libraries that has been working out really well in python i think and combines the best of the two worlds but someone has to write those libraries and those people probably also want to have a nice language to write in and sometimes it's just really awkward to express your program in terms of calling out to a C library because you need to use plain data types like arrays and numbers and need to get rid of classes probably and all the nice things you started loving about Python and now finally when people consider switching to Julia they will say well I have all these nice libraries but Julia actually has very nice foreign function interfaces for most major languages and one of the best developed one is actually Pycall so for calling Python and that's because historically the Julia and the Python community have been working a lot together. There's been a lot of people working together on this. So what can you do? By using PyCall you can just import any installed Python package, you can define Julia callbacks and just feed them into a Python function. Here this is just another syntax in Julia to have a short form of a callback. And this works just like passing a c function to pythons so it will have a similar performance you can also even inherit from python classes so this is a julia macro that gives you this kind of hybrid domain specific language between julia and python to define a python class that inherits from the polynomial from numpy and then you can just use it like a normal Julia type but also pass it to any Python function that accepts a polynomial and you can even write whole functions with this kind of string macro here this will immediately execute this in Python and define this pymap so that's just a very simple function it maps this function f over the array b and writes it out to a the result and we can wrap this in julia here and create this julia function pi map which we then can compare to the julia inbuilt so this is a funny little syntax here with a dot notation that you can apply any julia function to any julia array and it's pretty much like a map and it has a lot of nice properties but I'm not going more deeply into this. The same is true for calling C. So we have this little C snippet above there which implements the same function so it's also a map implementation. You can shell out to compile this little C function into a shared library and the code to actually call the C function is a bit more complicated because it's a statically typed language so you actually need to define with what types you call this function and you need to define the argument types and the return types of the function you're calling. But then you can just call the C function just like any Julia function and it will work without any overhead and finally there's also a C++ wrapper library called cxx.jl it's a bit more complicated because C++ is much more complicated so it actually also allows you via the string macro to define arbitrary C++ code which is very handy if you want to wrap more complex C++ libraries with templates and classes and then you can also call this C++ function with the CXX macro and call it just like any normal Julia function now let's talk a bit about performance since all those wrappers, even the PyCore wrapper shouldn't have any overhead it will just convert the array to a NumPy array I think, without any copies. Same is true for the C functions. So it's possible to benchmark those codes from inside Julia without any overhead. And I'm using benchmarks tools, which tries really hard to make statistically significant benchmarks. It's a bit awkward to call here, but that's how it looks. And now if we compare this, we see that Python takes 55 seconds for this simple map. C and C++ are around 1.1 seconds. And Julia is a bit faster than that, two times faster, I think. So in an extreme case, this is definitely an extreme case, Julia can be 600 times faster than Python for such simple things. Why is Julia faster than C++ and C? obviously you can get the same performance in C because it's very close to the hardware so you can always get the top performance but I think it's missing some SIMD optimization which is a bit harder to get in C and I didn't figure out the correct command line flex to get it but if you play around it you will get the same performance as Julia now can we go faster than this and the answer is yes Julia has pretty nice threading integration this at threads macro existed for quite a bit of time and with Julia 1.3 which got released a few months ago this threading infrastructure is way better nowadays but also a bit more complicated so I'm not going to talk about it today but yeah you can just make loop threaded with this macro and be even two times faster than the fastest Julia before. And since Julia has a very nice GPU integration, you can even easily move things to the GPU and then call the already existing map function and be even faster after that. What I want to point out here is that this actually does compile Julia functions to the GPU. so it's not restricted to some arbitrary set in queue arrays but you can write your own Julia functions and map them over an array or write your own CUDA kernels in Julia while using all the nice abstractions from Julia which is pretty unique now that means utilizing all these tools in Julia you can be up to 180 times faster than the C solution. Of course, that's not fair. Of course, you could go to C and also go through all these hoops and call out to the GPU. But I think what I want to point out here is that in Julia, it's very easy and you just have all these tools readily available. And the takeaway from this is Julia does offer state-of-the-art performance. it's relatively simple to get there and it has great interop there's also even javacall rcall and you can call to matlab which I haven't showed and while offering all of this it still stays interactive and fun now in the last two years or so there has been a new motto been forged in the Julia community is come for the performance stay for the syntax because a lot of people were actually like, yeah, I really need this performance of Julia, that's why I'm using it. Then they were writing more and more libraries and they were more excited about the actual syntax features and how you compose code in Julia. And that it's actually nice to have a type system compared to just having everything untyped. And multiple dispatch has been come up as a very nice way to compose code and extend existing libraries and i hope that this isn't too much code to simply point out what i'm talking about so above here we define a module that's how you can structure your julia code in isolated modules you can have abstract types in julia which are defined like that then you can have concrete types i already made a more advanced concrete type with the type parameter that means these fields can take on any type but they need to be the same one here and it inherits from an abstract color now in julia instead of binding methods to the object you actually just overload functions so here you just overload the base tuple function to convert your RGB value to a tuple and then you can also overload the plus operator here and this syntax says overload this for the argument T for all T that are inherent of abstract color and then we just convert to a tuple, do the plus with the tuple and create a new instance of the type T and having this base package means we can very easily define a new type like a new color space for example that inherits from abstract color and all we need to do is define this tuple conversion and we get the plus for free so this just works out of the box and that makes it very easy to combine packages especially because you then can just put it into a sum function which just expect your data type in the array to have plus defined for it. So this works out of the box and what's also pretty outstanding in Julia is that it has the same performance as built-in types so when you compare this to building the sum over three times as many floats you will see it has almost the same performance as doing it with the more complex types that wraps three floats and that means you can actually define your own number types if you want to track your accuracy in a simulation and things like that or dual types complex types they don't need to be built in enjoyer to actually be fast now some catchy examples i selected from data signs. This is the state-of-the-art CSV parser, which is by now in performance on par with the fastest CSV parsers there are. DataFrames is, yeah, obviously the DataFrame library in Julia. And there's Plots, which is the go-to plotting packages. And StatPlots is actually just an extension of plots and it's very similar to this extension color extension thing i showed you so just extending plots by a few more functions and this kind of domain specific syntax to more concisely make statistically statistical plots and i don't i mean you can have a look at it i won't go through this i will also publish the slides so you can probably look at it in more detail compared to it there's also query.jl and quite a few other data transforming packages this one uses Julia's macros to define a domain specific language to have a more concise way of defining data transformation and it's tightly integrated with VegaLite for plotting so that works very well together I think everyone just needs to find out which style they prefer more, and there are quite a few Julia libraries for that. Julia also has a neural network library, which is called Flux. Its features compare roughly to what TensorFlow offers. Mostly it's as fast, but because there are fewer people working on it, there are definitely some performance bugs. It uses the Julia GPU acceleration infrastructure, which allows the framework to be 100% written in Julia while still having GPU acceleration and the last time I checked the implementation was around 2000 lines of code so it's really approachable you can actually go in there and look at the code and understand what's going on which is very nice if you need to debug something and it also works with plain Julia arrays, types and functions because usually you can't do that because you need some GPU acceleration, but because Julia can actually compile those functions for the GPU and also has some pretty good automatic differentiation for custom functions, you can use those in your layers. This is how it looks like, just to give you a taste. there are many more examples like this in the flux model zoo if you're interested in this library and yeah i think it's a very promising library because i know i don't know if you know the tensorflow and swift project but it's very similar to that because um it's actually using compiler plugins instead of writing a new compiler around it to get good performance and that's where we come to hook into the compiler because Julia actually allows you to hook in very easily into the compiler and one of the main packages that make it possible is this cassette library how it works is that you define a new context in which you execute functions and in this context you can completely rewrite anything that gets called and any function that gets called in this context so for a simple thing there's this pre-hook function that gets executed before any call and i'm just using it to print what i'm calling next and if i then multiply for example execute a multiply in this context i will see the whole call stack for this and if you're saying now wow that's a lot of function calls for a simple multiply that's true because there's a whole promotion engine and things like that but this actually gets compiled down to be as fast as c because all of these are free abstractions in the compiler what you can also do is you can actually change the implementation of a function here i'm just doing something really silly i just overwrite the convert function and multiply it by 3 which completely changes our result but this is very powerful and can be used for implementing automatic differentiation and things like that or also there's a package that uses this to rewrite loops to execute them on the GPU and things like that and this all just works based on the Julia just-in-time compiler and is as fast as if you would execute it directly the resulting code I also wrote an interactive library it's super early this is probably the first time I'm showing it I'm hoping it's still running ah, it's not the problem is Next Journal shuts down the runner after 20 minutes and I guess it has been 20 minutes this needs to communicate with the Julia process in order to update the values but how it works is you can just use the markdown syntax pretty much and you can interpolate sliders and values into it and they will just update accordingly so this should update the plot in here much like PyWidget it's very similar it also runs in jupyter it also runs in the atom ide and you can also just serve it as a web page all right um i guess this is probably going through some people's mind right now um so yeah it's really hard to leave a language if you're already all your colleagues work in it. You have a lot of libraries you really like. But if you're really serious about Julia and want to offer your colleagues to still work with your packages that you write in Julia, it's possible. There's good news and bad news. There's possible is the good news. The bad news is that it's not that used at the moment. So I had quite a few problems getting this to run but in the end it was running so there's the Julia package in Python, you can just start importing any Julia package much like the PyCall example before but the other way around then I wrote a bit of wrapper code just to make it a bit nicer to use and then you can just call, this is my plotting library you can just call it from python with numpy arrays and with keyword arguments and everything it works now what's bad um you probably already see here 88 seconds execution time which is really bad for a language that i just sold you as to be super fast this is all compilation time and yeah that's really bad but um there you can compile it ahead of time um but it still doesn't work completely it's a bit of a hassle so people just do it if they're really forced to if they want to deploy it or things like that and actually it's not such a big problems for most juria developers because if you develop locally you will just start juria one time load all your packages and from there on you will only compile diffs so any new function you define and that will be instantly um so after everything compiled you will have pretty much the same latency as in python but it can get annoying especially if you try to compute something in the cloud where where it's expensive to just waste computations and things like that but um yeah deploy is also bad it's related because usually you want to compile things ahead of time if you deploy it it's a work in progress so some people are already deploying Julia to different platforms but they had to do it with a lot of manual work to get it running I'm actually working on a package to improve this but it's a slow progress because I don't have that much time, other people are working on it but it's happening and that brings me to my last point when should I use Julia I think library authors that need high performance and complex mathematical code I think I can say you can immediately start using Julia because it's really fun to write libraries in it especially if they're from scratch and not super large with a lot of compilation times and if you want smooth deploy and smooth ahead of time compile compilation i think that's probably ready in one to two years and the compiler team is working a lot on having a half interpreted mode and half compiled mode so then you will get the best of python and juya in one language but that will take some time and i think in three to five years You can probably expect that most problems in the ecosystem are fixed. Probably some ecosystems will still not be as nice as in Python because nobody invested time in it. But I think in the really serious areas, we will have it in one to two years. All right, thank you. Maybe I should... I don't have a session share. Any questions? Yeah. I can also do your Q&A for the rest. Thanks. Now... Is this on? It was. Okay, good. When I started learning Python, I didn't know about PEP 8, so I wrote a lot of code that didn't look nice. When you begin in Julia, is there anything about code style you should know when you begin? um if there's anything about code style yeah i think there's some no-goes um people usually some people come from other object-oriented languages and write to the forum how can i write object-oriented in julia and everyone is just like no don't do this we have something better um and there are some style guides out there they're a bit ignored i think um but the document the official documentation has some comments about what you should avoid and what you should be doing like when you should type your signatures of your functions and things like that other questions hey um from your presentation as far as i understood you can directly inherit from classes in python is that correct and can you a little bit elaborate so how that works do you get all that you have in python like everything predefined upper the hierarchy in julia and how you call it, like just for wrapping my brains around it. Yeah, so I think how it works is that this macro actually generates Python code to define a Python class. And whatever function you passed in there or defined in there will get passed to the Python class as a Julia function that then gets called as a method inside that class. so it's very similar to passing a callback function and then you just have a thin Julia wrapper around that Python class on the Julia side but it takes like some Python engine and it goes through regular Python distribution that you have so you need to have both or like how's it getting together I need to need both both of what uh so it's just taking python code and do you need the python distribution itself so does go through python engine to ah yes yes you need to have a python installation okay thanks any other questions okay thanks for the oh well sorry there's no question thanks um so one thing i really like about python is that the code is very readable um and just judging from the examples that you showed it didn't look as um readable i'd say to me so um would you say that um so in the beginning there's like is it hard to grasp the syntax so is there like a learning steep learning curve um i guess it depends on where you come from python yeah i've i haven't been coming from python so i can't completely judge it i just know that there are a lot of math examples where the math looks much nicer in julia of course if you're really set on object-oriented programming will it will usually take some time to grasp how to write things in julia yeah I think usually the syntax is as nice and comparable as Python there are a few things like people don't like the and in Julia but I think that's nitpicking if you write an and or if you leave it open we write and and don't have any like tab problems in Julia so I don't know I think these are minor things but there are definitely some examples I should have linked them all I will probably update the slides where you can really see how much nicer you can sometimes it's a problem in Julia of course they're probably the other way around sometimes but yeah okay well thanks for your talk alright thank you