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

Parallelization: switch from multiprocessing to joblib #137

Merged
merged 5 commits into from
Dec 4, 2023

Conversation

Ziqi-Li
Copy link
Member

@Ziqi-Li Ziqi-Li commented Dec 3, 2023

This PR replaces the repvious multiprocessing.pool based parallelization to joblib based. Users only need to specify the n_jobs parameter instead of passing a pool.

Example use:
GWR

n_jobs = 8
bw = Sel_BW(coords, y, X, n_jobs= n_jobs).search()
GWR(coords, y, X, bw, n_jobs=n_jobs)

MGWR

n_jobs = -1 #use all
mgwr_selector = Sel_BW(coords, y, X, multi=True, n_jobs=n_jobs)
mgwr_bw = mgwr_selector.search()
mgwr_results = MGWR(coords, y, X, selector=mgwr_selector, n_jobs=n_jobs).fit()

The test sets are updated to reflect the new interface. The notebook example is also updated and the effectiveness can be compared here: joblib-based (new) vs. mp-based (old)

@jGaboardi jGaboardi added the enhancement New feature or request label Dec 3, 2023
@TaylorOshan TaylorOshan merged commit 524f346 into pysal:master Dec 4, 2023
6 checks passed
Copy link
Member

@martinfleis martinfleis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for being late but I made two comments in the code.

At least the one on hard-breaking change would be good to resolve imho.

@@ -86,6 +87,10 @@ class GWR(GLM):
name_x : list of strings
Names of independent variables for use in output

n_jobs : integer
The number of jobs (default 1) to run in parallel. -1 means using all processors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I am coming late to the party but would you consider using -1 as a default? That is quite common across ML world and it is what users generally expect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was curious what others' opinion was on this... i tend to default to -1 personally, but joblib itself [indirectly] defaults to 1, and in esda we do both (join counts are conservative, G defaults to -1, etc)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think scikit usually defaults to 1 so i dont think there's a standard expectation in ML world

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind either as long as it is documented (which it is). But for heavily parallelisable code like this one, I tend to prefer parallel execution by default.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was only looking at scikit-learn and adapts to what they have. I actually personally prefer -1 as the default.

@@ -285,7 +291,7 @@ def _local_fit(self, i):
return influ, resid, predy, betas.reshape(-1), w, Si, tr_STS_i, CCT

def fit(self, ini_params=None, tol=1.0e-5, max_iter=20, solve='iwls',
lite=False, pool=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a hard-breaking change we should avoid. I suggest keeping the keyword and warning when it is not None.

@martinfleis
Copy link
Member

Another note, looking at the notebook. The section Effectivenss of n_jobs has a typo in the title but more importantly, can be misleading. The curve applies to a machine that likely has 8 effective cores and would look very differently on one with more or less. I think it deserves at least a line of a comment pointing this out.

@Ziqi-Li
Copy link
Member Author

Ziqi-Li commented Dec 4, 2023

Another note, looking at the notebook. The section Effectivenss of n_jobs has a typo in the title but more importantly, can be misleading. The curve applies to a machine that likely has 8 effective cores and would look very differently on one with more or less. I think it deserves at least a line of a comment pointing this out.

Nice catch on the typo. Will fix it.

I think the curve looks like this because 1) the data is still small 2) the linear part of the computation limits it from further scaling. Here the curves are just showing the parallelization works, the specific scalability depends on so many factors.

@martinfleis
Copy link
Member

The linear part of the computation limits it from further scaling

Only because of the number of available cores, no? If you ran the same code on a 32 core CPU, the minimum would be at 31-32, not 8 like here.

@Ziqi-Li
Copy link
Member Author

Ziqi-Li commented Dec 4, 2023

The linear part of the computation limits it from further scaling

Only because of the number of available cores, no? If you ran the same code on a 32 core CPU, the minimum would be at 31-32, not 8 like here.

I forgot to mention I have 12 physical cores on the machine. Will you suggest to add a note in notebook saying this is based on a 12-core machine.

@martinfleis
Copy link
Member

Will you suggest to add a note in notebook saying this is based on a 12-core machine.

Yes, that is what I meant.

It is interesting that it does not scale linearly to 12 cores...

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

Successfully merging this pull request may close these issues.

5 participants