Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can we use Numba?... #2646

Closed
portnov opened this issue Oct 31, 2019 · 35 comments
Closed

Can we use Numba?... #2646

portnov opened this issue Oct 31, 2019 · 35 comments
Labels
Discussion numba nodes or scripts that use `numba` Performance 🚀 snlite script scripts for snlite

Comments

@portnov
Copy link
Collaborator

portnov commented Oct 31, 2019

This is yet another topic about performance. Link: http://numba.pydata.org/
Numba is a jit-compiler for python. I managed to install it with pip into blender's python, and on simple examples like

from numba import jit

@jit
def main():
  result = 0
  for i in range(1000000):
    result = result + i
  return result

it gives about 10x boost.

While this looks very promising, it has one problem: it can't effectively handle the switch from JIT-ed code into not-jit-ed. I.e. if you make a call from function marked with @jit to function which is not jit-ed, Numba will switch back to plain interpretation mode and there will no boost anymore. For example, you can't call functions from python standard packages... one exclusion is numpy: Numba is especially aware of numpy and works effectively with numpy calls.

So. Do we have complex places, that require speedup and do all work by theirselves, without calling for external functions/libraries (except for numpy)?

I tried with "bend along surface" node — no luck, there is a lot of calls from it to outside and then again into node...

@zeffii
Copy link
Collaborator

zeffii commented Oct 31, 2019

i think inset_specials is self contained.

@zeffii
Copy link
Collaborator

zeffii commented Oct 31, 2019

and uv_connections

@portnov
Copy link
Collaborator Author

portnov commented Oct 31, 2019

https://stackoverflow.com/questions/56792853/numba-v0-44-cannot-reflect-element-of-reflected-container/56794390

Numba as of 0.44 does not support list of lists as inputs to functions in nopython mode.

:(
we use nested lists a lot. So it seems there is no easy way: one cannot just put @jit everywhere and be happy. Code has to be specifically written for numba.

@portnov
Copy link
Collaborator Author

portnov commented Oct 31, 2019

(more specifically, it does support nested lists, it just switches back to interpreting mode, so becomes useless).

@zeffii
Copy link
Collaborator

zeffii commented Oct 31, 2019

if it doesn't work on nested lists, would it accept "unrolled lists" , with information about nesting, then use that representation in the decorated function?

@zeffii
Copy link
Collaborator

zeffii commented Oct 31, 2019

maybe the preprocessing step of "flattening" would take up more time than saved by the numba stuff. hehe..

@portnov
Copy link
Collaborator Author

portnov commented Oct 31, 2019

Yes, it'll work with "unrolled" lists. Also it will work with numpy arrays.

@alessandro-zomparelli
Copy link
Collaborator

alessandro-zomparelli commented Nov 11, 2019

Hi guys, I'm using Numba in the Tissue Reaction-Diffusion code, and for me it gave a boost of 500 times @_@
It seems to work better with python for loops rather than numpy operations and allows parallel execution. It's insane.
I highly recommedn to use it in some part of the code. It works great with numercial operations/expressions, but doesn't allow to use calls from other modules. So maybe it could be used for creating some low level optimized functions to call from the different nodes (addition, multiplication, power, frequently used expressions, etc...).
Also, I would recommend to avoid nested list in general, in my opinion they are not the most efficient way to handle complex data structure and they make difficult to hanlde different data structure each time.

@portnov
Copy link
Collaborator Author

portnov commented Nov 11, 2019

Yeah...

  1. numba is good for "self-contained" code, when you have one function or several functions, that are called from each other, but never do "outside" calls. Unfortunately, there are not many such places in Sverchok. In fact, you have to write the code in this style, you can't just mark any random code with @jit and be happy.
  2. python's nested lists, and lists in general, are not too effective. Numpy's multidimensional arrays are much more effective. There were... well.. impulses to rewrite the whole Sverchok to use numpy arrays instead of lists; but they never got too far.

@alessandro-zomparelli
Copy link
Collaborator

@portnov , I would love to help rewriting Sverchok, at least for a comparative test. It would be greatto use numpy + numba for example for the math node and other numerical operations. This would give a huge boost and much more stability to the data structure.
Still, one of the other weakness is that it recompute the whole tree even with a small change in one part of it, but I don't know if this is a limitation of the Blender's Node System in general.

@portnov
Copy link
Collaborator Author

portnov commented Nov 11, 2019

is that it recompute the whole tree

It's a weakness in Sverchok itself. There are some efforts to do not recalculate what obviously should not be, but these algorithms can be enhanced. There are even issues in progress about that - see #2380, #2439, #2393 ...

See also https://github.com/Sverchok/Sverchok — I believe this is the latest attempt to rewrite sverchok...

@adalbert-homa
Copy link

Animation nodes is using cython.
See: https://animation-nodes-manual.readthedocs.io/en/latest/dev_guide/index.html

@portnov
Copy link
Collaborator Author

portnov commented Dec 16, 2019

That requires developers (or, even worse, users) to build something, for each operating system supported. We do not want to do so: sverchok is installed by downloading zip file directly from github and pressing a button in preferences. We do not want to make this process any more complicated.
Though, we can imagine some kind of "sverchok booster" addon, which would be built for specific platform, and then installed into Blender on top of sverchok.

@kosirm
Copy link

kosirm commented Feb 15, 2020

Tissue plugin (dev branch) is using Numba module and it is not complicated at all. For new users some simple tutorial can be done, I think. Just my 0.2 $

@portnov
Copy link
Collaborator Author

portnov commented Feb 15, 2020

Yes, Numba has the advantage of not requiring compilation. But, as I mentioned before, it actually requires to write code in a specific way. So one can't just "add numba and be happy".

@kosirm
Copy link

kosirm commented Feb 17, 2020

This is beyond my domain :) Thanks for explanation!

@zeffii
Copy link
Collaborator

zeffii commented Jul 7, 2020

@portnov these are interesting things. this numba njit stuff.

@zeffii
Copy link
Collaborator

zeffii commented Jul 7, 2020

this was an interesting video : https://www.youtube.com/watch?v=x58W9A2lnQc

@nortikin
Copy link
Owner

nortikin commented Jul 7, 2020

i hope i have time for 'list zip', 'list flip', 'waffle', 'uvconnect' to rewrite, and with numpy/numba support. than i will just brutally cut or extend python lists for equal numpy.array.
About waffle node it is more useful to have it as surface/curve or solid solution.

@zeffii
Copy link
Collaborator

zeffii commented Jul 7, 2020

okidoki :)
on windows

python\bin> ./python.exe -m pip install numba

@zeffii
Copy link
Collaborator

zeffii commented Jul 7, 2020

i will need to find a way to make this work in SNlite node.. i don't dare assume it will work just-like-that :)

@zeffii
Copy link
Collaborator

zeffii commented Jul 7, 2020

oh wow. just the first call is slow.. as expected from the docs..

"""
in num_items s d=100 n=2
out dummy s
"""

from numba import jit
import numpy as np
import time

x = np.arange(num_items).reshape(10, 10)

@jit(nopython=True) # Set "nopython" mode for best performance, equivalent to @njit
def go_fast(a): # Function is compiled to machine code when called the first time
    trace = 0.0
    for i in range(a.shape[0]):   # Numba likes loops
        trace += np.tanh(a[i, i]) # Numba likes NumPy functions
    return a + trace              # Numba likes NumPy broadcasting

start = time.time()
print(go_fast(x))
end = time.time()
print("Elapsed (with compilation) = %s" % (end - start))  # Elapsed (with compilation) = 2.9859113693237305

start = time.time()
print(go_fast(x))
end = time.time()
print("Elapsed 2 (with compilation) = %s" % (end - start))  #  Elapsed 2 (with compilation) = 0.007998228073120117

@zeffii
Copy link
Collaborator

zeffii commented Jul 7, 2020

so it has an ahead-of-time compilation mode, which i think would need to be run by the individual-user's computer once before using. https://numba.pydata.org/numba-doc/latest/reference/aot-compilation.html#aot-compilation

@zeffii
Copy link
Collaborator

zeffii commented Jul 8, 2020

we have many functions that are heavy, not because the logic is heavy but because regular python has prohibitive overhead or numpy doesn't lend itself well because the algorithm isn't easily sanely expressed as a matrix multiplication/etc :)

@zeffii
Copy link
Collaborator

zeffii commented Jul 8, 2020

so @portnov i'm a total convert.

@zeffii
Copy link
Collaborator

zeffii commented Jul 8, 2020

slightly modified:

pacakge rd_test

  • __init__.py (empty)
  • reaction.py (below)

reaction.py

# Turing Pattern Formation
# intro to modelling and analysis of complex systems
# https://math.libretexts.org/Bookshelves/Applied_Mathematics/Book%3A_Introduction_to_the_Modeling_and_Analysis_of_Complex_Systems_(Sayama)/13%3A_Continuous_Field_Models_I_-_Modeling/13.06%3A_Reaction-Diffusion_Systems

from numba import njit
import numpy as np


@njit
def reaction_test(steps, n=40, a=1.0, b=-1., c=2., d=-1.5, h=1., k=1.):
    # pylint: disable=c0103

    # n = 40  # size of grid n*n
    Dh = 1. / n  # spatial res, assuming space is [0, 1] * [0, 1]
    Dt = 0.02 # temporal res

    # a, b, c, d, h, k = 1., -1, 2., -1.5, 1., 1. # param values
    Du = 0.0001  # diffusion constant of U
    Dv = 0.0006  # dif  V

    u = np.zeros((n, n))
    v = np.zeros((n, n))
    for x in range(n):
        for y in range(n):
            u[x, y] = 1. + np.random.uniform(-0.03, 0.03)  # small noise is added
            v[x, y] = 1. + np.random.uniform(-0.03, 0.03)  # small noise is added
    nextu = np.zeros((n, n))
    nextv = np.zeros((n, n))

    for iteration in range(steps):
        for x in range(n):
            for y in range(n):
                # state-transition function
                uC, uR, uL, uU, uD = u[x, y], u[(x+1) % n, y], u[(x-1)%n, y], u[x, (y+1) % n], u[x, (y-1) % n]
                vC, vR, vL, vU, vD = v[x, y], v[(x+1) % n, y], v[(x-1)%n, y], v[x, (y+1) % n], v[x, (y-1) % n]

                uLap = (uR + uL + uU + uD - 4 * uC) / (Dh**2)
                vLap = (vR + vL + vU + vD - 4 * vC) / (Dh**2)
                nextu[x, y] = uC + (a*(uC-h) + b*(vC-k) + Du * uLap) * Dt
                nextv[x, y] = vC + (c*(uC-h) + d*(vC-k) + Dv * vLap) * Dt

        u, nextu = nextu, u
        v, nextv = nextv, v

    return u.ravel() > v.ravel()

snlite script

"""
in steps s d=100 n=2
in size s n=40 d=2
out nparray s
"""

from rd_test.reaction import reaction_test

uravel = reaction_test(steps, n=size)
nparray.append(uravel)

image

@zeffii
Copy link
Collaborator

zeffii commented Jul 9, 2020

@portnov
Copy link
Collaborator Author

portnov commented Jul 9, 2020

Well, RD stuff looks nice, but I'm not sure where to apply it in Sverchok. Generate textures?

About geometry: I'll try to @jit some differential-geometry functions which appeared in sverchok lately (bezier curves, offset nodes, curvature calculations...). Will see if it is possible to refactor them so that they do not call non-jit-ed code.
Not sure if it will do any good though. All these things are already use numpy (= written in C++ mostly).

@zeffii
Copy link
Collaborator

zeffii commented Jul 9, 2020

i'm rewriting inset_specials , or attempting.. it does require taking a few steps back.

i read however that nested functions are now supported in numba.jit , as long as those functions are not recursive. and don't themselves return a function.

@zeffii
Copy link
Collaborator

zeffii commented Jul 11, 2020

there are 2 major functions that i'm failing to implement a foolproof solution to, the one builds on the other.

  • triangulate an ngon
  • find the normal of any vertex_list

where the criteria are expect the following input

  • i. tris (duh..not the problem)
  • ii. quads ( 1. concave, 2. colinear edges 3. convex )
  • iii. ngons ( 1. concave, 2. convex )

in particular the ii.3 and iii.2 cases, maybe borrow from the scanline algorithm and mathutils.geometry.normal(vertlist) and rewrite the C code as python first. Remarkable lack of "out of the box" search results. lot's of proprietary solutions tho :)

@portnov any tips before i get entrenched down this rabbit hole ?

@portnov
Copy link
Collaborator Author

portnov commented Jul 11, 2020

You can look at blender's source, how it calculates normals.

@portnov
Copy link
Collaborator Author

portnov commented Jul 11, 2020

One of possible options is to find the "best fit" approximating plane for all vertices with least squares method and take it's normal (see sverchok.utils.geom.linear_approximation). But that may be too heavy.

@zeffii
Copy link
Collaborator

zeffii commented Jul 11, 2020

yeah, i'll distill the blender method (if it's the last thing i do)

my pride takes comfort in the fact that tessellation is sometimes someone's topic of BS thesis, a non trivial stuff.. is always hard to find clean examples of

@zeffii
Copy link
Collaborator

zeffii commented Jul 20, 2020

cool numba talk: https://www.youtube.com/watch?v=-4tD8kNHdXs (30+ minutes. really no-nonsense )

@zeffii zeffii added the snlite script scripts for snlite label May 26, 2021
@zeffii zeffii added the numba nodes or scripts that use `numba` label Jul 6, 2021
@zeffii zeffii closed this as completed May 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Discussion numba nodes or scripts that use `numba` Performance 🚀 snlite script scripts for snlite
Projects
None yet
Development

No branches or pull requests

7 participants