I’m trying to port an Machine Learning app that was written in Python using Pytorch to Julia and I’m a newbie in Julia.
Is there a resource,cheat sheet that show how the same thing work in Julia for examples
Python Julia
class ?
init ?
call ?
iter ?
**kwargs ?
etc…
I’ve been reading Julia doc but would take too long I want to get this done a little faster
Are you asking for help woth those specific things or a resource for the machine learning functions?
- Classes don’t exist in Julia
- Init isn’t necessary to create structures. Loook at Constructors · The Julia Language
- Iterators are pretty broad and what you want to do will depend on the type of iteration.
- You can just write
methodname(; kwargs...)
If you intend to actually use Julia besides porting one application, you’ll probably be better off learning Julia properly. The documentation and several available tutorials are available for that. It quickly pays off when you don’t have to consult online forums for simple things.
I thought some one have done this before porting their Python app over to Julia
they might have some resource that they used willing to share on the net.
I’m sure similar things have been ported over but it’s unclear what you would need. There’s not a general “How to convert Python to Julia” guide (although I’m sure there’s some sort of numpy to julia guide out there).
There’s not an exact PyTorch equivalent, but there are several neural net libraries. You can get a lot done with Flux.jl. I’m not personally familiar with Knet.jl, but I’ve heard it’s well implemented and easy to use. You could also use Tensorflow.jl which you might prefer if you’re familiar with Tensorflow but want the benefits of Julia.
Those libraries will give you a good idea of how to port standard layers that you’re probably use to in other ML libraries, but Julia takes an entirely different approach than the Python mega libraries out there. With Julia you can have many libraries be interoperable but still be fast. In Python each library has to reinvent a lot of stuff for their own use. In other words, you will likely need lots of tools that are much less involved than learning all of PyTorch.
Thank for the suggestion.
No problem. Feel free to ask more questions here. The Julia community is very friendly to newcomers.
You may find this useful: Noteworthy Differences from other Languages · The Julia Language
I have recently worked through porting Lark (a Python parsing package) to Julia. Some little things to be prepared for:
- A single character ‘a’ and a single character string “a” are different in Julia, unlike Python. Equality tests in Julia will therefore fail where they succeed in Python. In general, make sure you know when a Julia function returns a character. You can add a method in Julia to make them equal, of course.
- Do you know how the syntax
a,=b
works in Python? In Julia? Check it out! - Make sure you know the difference between
push!
,append!
in Julia and Python’sappend
,extend
,+=
. Hint:append
works differently. - Python code loves things like
if b:
, where None and empty both count asFalse
.nothing
and an empty string/list/tuple are notfalse
in Julia. - Make sure that both Julia
hash
and==
behave the same way as Python for your complex structures. I spent the most debugging time discovering that functions like unique!, Set(), Dict() had slightly different ideas as to the contents of lists and sets than I had. - The Julia “join” function takes the joining string as the final argument, not the first.
To answer your original question, I do not know of a cheatsheet, and I suspect each Python codebase will be approached differently depending on the particular coding philosophy.
The strategy I took with __init__
was to define one or more outer constructors for that type.
**kwargs
are handled by “splatting”" and “slurping”.
The only use of __call__
in my source codebase appeared to be a way of passing around a closure in an object…so I just created a closure in Julia.
I didn’t have to work with __iter__
. Python generator functions (containing yield
) can be modeled using unbuffered Julia Channels. But beware: as Python is single-threaded, the code after the yield
is not executed until whichever code was yielded to calls back into the generator. However, in Julia code following a put!
is executed as soon as the value is read, and runs right up until the next put!
. So, if the Python code calling the generator sees fit to mutate any structures that the generator is using after it has received the value but before it calls for the next value, then the Julia code may diverge in behaviour, as it will be running in parallel with the generator, unlike the Python code. The way I solved this was to have a two-way channel so that the calling function had to send a dummy value back to allow calculations to proceed.
None of this is to imply that it might not be better to restructure the Julia code to use more natural Julia structures. As this codebase was not my own, I didn’t feel confident in getting too fancy until I had all the tests passing.
Thank, this is what I’m looking for you should put this on cheat sheet or web site,so those of us that come after you don’t have to spend hour debugging them to find out that it works a little differently. May be later when I have more time and better understanding of Julia I’ll rewrite it in Julia
Yes, It’s been helpful, thank.
I am in about the same position as @vphom - I just started to learn Julia, and I have a small application or two, which I would probably like to port from Python and further develop it in Julia. “Probably” in my case because whether we will really need the applications depends on many circumstances.
So in one case I started with the Python application and tried to port the most computational expensive part of it to Julia, than call it from Python through pyjulia. That actually worked on one of the computers, while on another one I couldn’t properly install it. Thus I could port the module function by function and check results against the original program.
To the list of the things to be prepared for (@frtps , thank you for your post), I would like to add one more - the scoping rules as discussed here: Dicussion on scoping rules . The nasty thing is that in many cases your try
blocks and loops would work in Julia just as in Python - because you just happend to initialize the corresponding variable in some way.
As a general remark - from my recent experience: Julia may look familiar on the first glance, but pretty soon you will find out you need to invest time in reading at least a big part of the manual anyway.
Also:
I recently wrote two libraries with the same functionalities in Julia and Python.
In both version, I tried to make them as Julian and Pythonist as I could.
This includes some design considerations like inheritance (normal in Python) vs composition (normal in Julia), as well as class design and the use of macros in Julia.
There are also some differences in python vs julia syntax, like you mentioned: init, call, iter, kwargs.
Hopefully it can help. Here are the links:
Julia version: GitHub - rizalzaf/AdversarialPrediction.jl: Easily optimize generic performance metrics in differentiable learning.
Python version: GitHub - rizalzaf/ap_perf: Easily optimize generic performance metrics in differentiable learning.
I also realized that those projects may not be the best way to write code in the best Julian and Pythonist way. Let me know if there is any suggestions.
A short comparison of the structure / concepts between both languages, as far as I understood, maybe this is helpful for you. Please correct me if I am wrong.
Python name | Python meaning | Julia name | Julia meaning |
---|---|---|---|
def f(x,y): |
named function - duck-typing, no polymorphism | fuction f(x,y) |
duck-typing, multiple dispatch to methods |
lambda x: x |
anonymous function | (x) -> x |
anonymous function |
class MyClass(Parent) |
classical OOP class, multiple inheritance | struct MyStruct{TypeParameters} <: AbstractParent |
data and constructor only, types inside struct can be parametrized, can inherit only from abstract types |
method | function that belongs to a class (single dispatch on first argument self ) |
method | function implementation for concete parameter types (multiple dispatch on all arguments) |
def __init__(self, x): |
constructor of a class, one per class | MyStruct(x) |
Constructor method (multiple constructors can be defined, selected using multiple dispatch) |
module | namespace - defined as a single .py file |
module |
namespace - defined independenly of file strucutre |
package | directory with __init__.py file |
NA | directory structure independent of logical structure |
package | bundled and installable, e.g. using pip , conda
|
package | includes dependencies (Project.toml ), installable using Pkg , very light-weight |
@decorator |
applies a higher order function to the following def , often used for wrappers |
@macro |
transformation which has Julia expressions (code) as input and output (very powerful) |
with block |
context manager, used for opening and teardown of resources |
do block |
content of the block is passed as anonymous function to function before do statement |
raise Exception |
raising Exceptions | throw(Exception) |
raising Exceptions |
try - except - finally
|
Exception handling, can be used as part of normal program workflow |
try - catch - finally
|
Exception handling, should not be part of normal program workflow due to performance reasons |
def init(self, x):
new
seems to be comparable.
It would be great if the results of this discussion were used to update
I found this great comparison of Julia, R, and Python syntax when poking around the Learning section of the JuliaLang homepage.
I support the idea.
Here are some additional differences I could think of.
- Julia requires
end
for indexing until the last element.x[1:]
in Python is equivalent withx[2:end]
in Julia. - Julia’s range indexing has the format of x[start:step:stop], whereas Python’s format is x[start:stop:step]. Hence,
x[0:10:2]
in Python is equivalent tox[1:2:10]
in Julia. Similarly,x[::-1]
in Python, which refers to the reversed array, is equivalent tox[end:-1:1]
in Julia. - In Julia, indexing a matrix with arrays like
X[[1,2], [1,3]]
refers to a sub-matrix that contains the intersections of the first and second rows with the first and third columns. In Python,X[[1,2], [1,3]]
refers to a vector that contains the values of cell [1,1] and [2,3] in the matrix.X[[1,2], [1,3]]
in Julia is equivalent withX[np.ix_([0,1],[0,2])]
in Python.X[[0,1], [0,2]]
in Python is equivalent withX[[CartesianIndex(1,1), CartesianIndex(2,3)]]
in Julia. - Julia’s
max
andmin
are the equivalent ofnp.maximum
andnp.minimum
respectively in Python. Whilemaximum
andminimum
replacenp.max
andnp.min
in Python. - The imaginary unit
sqrt(-1)
is represented in Julia asim
, notj
as in Python. - In Julia, the exponentiation operator is
^
, not**
as in Python. - In Julia, we use
nothing
of typeNothing
to represent null value, whereas Python usesNone
of typeNoneType
. - In Julia, the standard operators over a matrix type are matrix operations, whereas, in Python, the standard operators are element-wise operations. When both
A
andB
are matrices,A * B
in Julia performs matrix multiplication, not element-wise multiplication as in Python.A * B
in Julia is equivalent withA @ B
in Python, whereasA * B
in Python is equivalent withA .* B
in Julia. - The transpose operator
'
in Julia returns an adjoint of a vector (a lazy representation of row vector), whereas the transpose operator.T
over a vector in Python returns the original vector (non-op).
Good idea!
Let’s continue to collect and then make a PR.
How should we struture it best? Maybe one table for syntax (e.g. range vs. 1:10), and one for structuring, etc. (like functions, modules)?