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

Alternative query integral image #426

Closed
wants to merge 6 commits into from
Closed

Alternative query integral image #426

wants to merge 6 commits into from

Conversation

Aierie
Copy link

@Aierie Aierie commented Jul 31, 2018

Found a small kink in the goal generator - including 0 is inefficient
(and creates garbage with my subfunctions)

Tried cdef subfunctions to improve speed!

Also added a unit test file (WIP, not sure of the best way to handle Cython in unit testing).

I'm not very experienced in package creation, so I'm passing this over for a quick look. If it looks okay I'll give it a go!

Aierie added 2 commits July 31, 2018 10:18
Found issue with parameters to randint, including 0 in the range can cause inefficient searches

(or random garbage since c_search_for_space uses C arrays)

Fixed by changing random number generation to:

random.randint(1, hits)
-------------------------------------------
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-------------------------------------------
- Created subfunctions with cdef-

c_search_for_space
c_iterate_for_coordinates

Profiling with line_profiler shows that these are faster however it's been difficult to do good timeit testing with timeit on my computer due to specs

-------------------------------------------
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-------------------------------------------
Created test_subfunctions for unit testing purposes
Added unit tests for c_search_for_space
@jcfr
Copy link
Collaborator

jcfr commented Jul 31, 2018

Thanks for the contribution.

Since we recently transition to pytest for writing our tests.

Would it be possible to:

  • rename Unit_tests.py into test_hits.py (or similar name)
  • have a single function for each new tests added to the test_hits.py file (instead of creating a hierarchy of class).

To execute the test, run pytest from the top-level folder.

the best way to handle Cython in unit testing

Waiting, we make a decision on #424 , you have to locally regenerate the file wordcloud/query_integral_image.c file running cython wordcloud/query_integral_image.pyx

Then, testing will work as expected because we run pip install -e . before executing the tests. This ensure the module is compiled and available in the source tree.

@Aierie
Copy link
Author

Aierie commented Jul 31, 2018

Thanks @jcfr ! I'll give it a go.

Aierie added 3 commits July 31, 2018 15:12
Tests number of hits on blank np.ndarray for:
word size = (x, y)
word size smaller than array.shape
word size = array.shape[0] - 1, array.shape[1] - 1
word size = array.shape[0] + 1, array.shape[1] + 1
Changed the string passed to subprocess.check_call to be inclusive for windows users as it failed during my testing
@jcfr
Copy link
Collaborator

jcfr commented Jul 31, 2018

Thanks for the follow up.

To address the coding style issue locally, you can run:

flake8

in the top level directory of the project.

@Aierie
Copy link
Author

Aierie commented Jul 31, 2018

Hmm. Seems like there's still a fair amount of work to do with this - I'll download CircleCI and try and work on it! Thanks for the suggestions @jcfr ! Closing for now.

@Aierie Aierie closed this Jul 31, 2018
@jcfr
Copy link
Collaborator

jcfr commented Jul 31, 2018

Sounds good. It may also be worth sharing some timing result. That would help @amueller assess if moving forward with the approach is sensible.

@Aierie
Copy link
Author

Aierie commented Jul 31, 2018

@amueller

With this setup:

integral_image = np.zeros((400, 400), dtype=np.uint32)
size_x = 10
size_y = 10
random_state = random.Random()

Running timeit (10000 times) yields:
original query_integral_image: 18.97049316452103s
alternative: 15.947954525594469

%lprun -f query_integral_image -f alternative alternative(integral_image, size_x, size_y, random_state); query_integral_image(integral_image, size_x, size_y, random_state)

yields:
original query_integral_image: 0.219951 s
alternative: 0.00224246 s

Not sure about the dramatic difference in lprun but the jupyter notebook I used is here:
https://github.com/Aierie/testing_query_integral_image-alternative.git

I originally was attempting to implement an array storage of hit coordinates but found that this was reasonably fast!

@amueller
Copy link
Owner

@Aierie cool! Can you maybe run the timing using an actual word-cloud?

@Aierie
Copy link
Author

Aierie commented Aug 1, 2018

I've tried going with an actual wordcloud, and apparently it actually makes it slower.

original: 527 ms ± 3.19 ms per loop (mean ± std. dev. of 7 runs, 1000 loops each)
alternative: 562 ms ± 2.07 ms per loop (mean ± std. dev. of 7 runs, 1000 loops each)

I don't really understand why - any idea? I suppose this means that it's not too viable an approach.

    cdef int goal = random_state.randint(0, hits)
    hits = 0
    for i in xrange(x - size_x):
        for j in xrange(y - size_y):
            area = integral_image[i, j] + integral_image[i + size_x, j + size_y]
            area -= integral_image[i + size_x, j] + integral_image[i, j + size_y]
            if not area:
                hits += 1
                if hits == goal:
                    return i, j

I found this while working through the code:
Could consider changing
cdef int goal = random_state.randint(0, hits) to cdef int goal = random.randint(1, hits)
because getting goal = 0 automatically returns (0, 0) and affects sizing and placement, and search efficiency/termination. Should I open a pull for this?

Edit: returns (0, 0) assuming the area is occupied

@jcfr
Copy link
Collaborator

jcfr commented Aug 1, 2018

Could consider changing
cdef int goal = random_state.randint(0, hits) to cdef int goal = random.randint(1, hits)
because getting goal = 0 automatically returns (0, 0) and affects sizing and placement, and search efficiency/termination. Should I open a pull for this?

Did you get a chance to do some timing comparison within and without this optimization ?

@Aierie
Copy link
Author

Aierie commented Aug 1, 2018

Sorry, I'm confusing myself. 😬 i'm mixing up my code results with the original. With the original the worst that could happen is an overlap. I need a break I think 😂

@Aierie
Copy link
Author

Aierie commented Aug 1, 2018

Thanks for the tips guys! @jcfr @amueller Will be back when I'm better prepared!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants