-
-
Notifications
You must be signed in to change notification settings - Fork 26k
[MRG+1] NMF speed-up for beta_loss = 0 #9277
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
Conversation
how does **= -2 compare? it is strange to me that you would need to do two
**= operations to get the speedup.
…On 5 Jul 2017 9:07 am, "hongkahjun" ***@***.***> wrote:
Suggestion for speeding up IS divergence in NMF mu update:
WH_safe_X_data **= -1WH_safe_X_data **= 2
is much faster than
WH_safe_X_data **= beta_loss - 2
Using line_profiler on ipython to time the lines,
seconds
4363077 WH_safe_X_data **= beta_loss - 2
vs
219524 WH_safe_X_data **= -1
33966 WH_safe_X_data **= 2
test code below:
from sklearn.decomposition.nmf import non_negative_factorizationfrom sklearn.decomposition.nmf import _multiplicative_update_wfrom sklearn.linear_model import LogisticRegressionfrom sklearn.datasets import make_classificationimport timefrom IPython import get_ipythonimport numpy as np
ipython = get_ipython()
np.random.seed(10)
t0 = time.time()
all_samples, all_targets = make_classification(n_samples=1000, n_features=513, n_informative=511,
n_redundant=2, n_repeated=0, n_classes=2,
n_clusters_per_class=1, random_state=0)
all_samples += 5000
ipython.magic(
"lprun -f _multiplicative_update_w non_negative_factorization(all_samples, n_components=16, solver='mu', beta_loss='itakura-saito', max_iter=100)")
------------------------------
You can view, comment on, or merge this pull request online at:
#9277
Commit Summary
- NMF speed-up for beta_loss = 0
- newest update for NMF speed-up for beta_loss = 0
- updated NMF speed-up for beta_loss = 0
- updated NMF speed-up for beta_loss = 0
File Changes
- *M* sklearn/decomposition/nmf.py
<https://github.com/scikit-learn/scikit-learn/pull/9277/files#diff-0>
(11)
Patch Links:
- https://github.com/scikit-learn/scikit-learn/pull/9277.patch
- https://github.com/scikit-learn/scikit-learn/pull/9277.diff
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#9277>, or mute the
thread
<https://github.com/notifications/unsubscribe-auth/AAEz6yAaW5HQ2ohwpEFWVOngTwt7idjPks5sKsWsgaJpZM4ONuom>
.
|
Hi Sorry if I was not clear but WH_safe_X_data **= -2 yields 4217895 WH_safe_X_data **= -2 Also, not sure why it is much faster, but seems like it has something to do with how numpy calculates powers that are not positive integers. |
that seems faster than either option in your original benchmarks, unless
I'm not reading correctly
…On 5 Jul 2017 6:35 pm, "hongkahjun" ***@***.***> wrote:
Hi
Sorry if I was not clear but
WH_safe_X_data **= -2
yields
42178.9 WH_safe_X_data **= -2
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#9277 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEz60rLm_i4goxIzibbcMwsKEONJ67Cks5sK0rYgaJpZM4ONuom>
.
|
WH_safe_X_data **= -2 yields 4,217,895
while
WH_safe_X_data **= -1 yields 219,524
WH_safe_X_data **= 2 yields 33,966 |
sounds like a numpy issue potentially. what numpy configuration are you
using?
…On 5 Jul 2017 7:05 pm, "hongkahjun" ***@***.***> wrote:
WH_safe_X_data **= -2 yields 4,217,895whileWH_safe_X_data **= -1 yields 219,524 WH_safe_X_data **= 2 yields 33,966
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#9277 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEz60WvKJl4LYjj6wMULGRUq_VJwvyIks5sK1HHgaJpZM4ONuom>
.
|
Hi, I am using 1.11.3. |
Numpy.show_config()?
And how do those benchmarks look on latest numpy (1.13)?
…On 5 Jul 2017 7:24 pm, "hongkahjun" ***@***.***> wrote:
Hi,
I am using 1.11.3.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#9277 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEz6x65jlmyBIstFHwAXdziwLuc250rks5sK1Y1gaJpZM4ONuom>
.
|
Numpy uses different functions for power internally:
A benchmark on (Click on details to show the script) import numpy as np
from time import time
import matplotlib.pyplot as plt
n_points = int(1e6)
power_range = np.arange(0, 4.1, 0.1)
durations = np.zeros((2, power_range.size))
array = np.random.randn(n_points)
np.abs(array, array)
for i, power in enumerate(power_range):
array_copy = array.copy()
start = time()
array_copy **= -power
durations[0, i] = time() - start
array_copy = array.copy()
start = time()
array_copy **= power
array_copy **= -1
durations[1, i] = time() - start
plt.figure(figsize=(10, 4))
ax = plt.gca()
ax.plot(power_range, durations[0], '-o', label='one operation')
ax.plot(power_range, durations[1], '-o', label='two operations')
ax.set(xlabel='power', ylabel='time', title='Elementwise power in Numpy')
ax.legend()
plt.show() |
Thanks, @TomDLT!
so it sounds we should at least raise an issue at numpy to handle -.5 and
-2.
I'm okay with merging this for now, but I'd appreciate a comment
referencing fast_scalar_power (or the issue one of us is about to create at
numpy).
…On 5 July 2017 at 20:23, Tom Dupré la Tour ***@***.***> wrote:
Numpy uses different functions for power internally
<https://github.com/numpy/numpy/blob/b9e3ac9abb6e435cdf6bbe33e0bc894d6a879a53/numpy/core/src/multiarray/number.c#L464>
:
- When the exponent is in {-1, 0, 0.5, 1, 2}, it uses respectively {reciprocal,
one_like, sqrt, ~identity, square}.
- For any other exponent, it uses a much slower routine. This is why a
**= 2; a **= -1 is much faster than a **== -2.
A benchmark on a **= b; a **= -1 versus a **== -b gives me (v1.11.3):
[image: figure_1]
<https://user-images.githubusercontent.com/11065596/27860284-25fff35c-617c-11e7-8607-c07fb1b7aac1.png>
(Click on details to show the script)
import numpy as npfrom time import timeimport matplotlib.pyplot as plt
n_points = int(1e6)
power_range = np.arange(0, 4.1, 0.1)
durations = np.zeros((2, power_range.size))
array = np.random.randn(n_points)
np.abs(array, array)
for i, power in enumerate(power_range):
array_copy = array.copy()
start = time()
array_copy **= -power
durations[0, i] = time() - start
array_copy = array.copy()
start = time()
array_copy **= power
array_copy **= -1
durations[1, i] = time() - start
plt.figure(figsize=(10, 4))
ax = plt.gca()
ax.plot(power_range, durations[0], '-o', label='one operation')
ax.plot(power_range, durations[1], '-o', label='two operations')
ax.set(xlabel='power', ylabel='time', title='Elementwise power in Numpy')
ax.legend()
plt.show()
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#9277 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEz6840CUZglxqDvaGKWKDCp-973C95ks5sK2QjgaJpZM4ONuom>
.
|
@TomDLT will you report at Numpy? |
All right, I added a comment stating that code is using numpy's reciprocal function for exponent -1 |
sklearn/decomposition/nmf.py
Outdated
@@ -545,6 +545,12 @@ def _multiplicative_update_w(X, W, H, beta_loss, l1_reg_W, l2_reg_W, gamma, | |||
|
|||
if beta_loss == 1: | |||
np.divide(X_data, WH_safe_X_data, out=WH_safe_X_data) | |||
elif beta_loss == 0: | |||
# using numpy's reciprocal function for exponent -1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're effectively using np.reciprocal and np.square, you could just do that here...
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for merge once CI is green.
Thanks @hongkahjun |
Suggestion for speeding up IS divergence in NMF mu update:
is much faster than
Using line_profiler on ipython to time the lines,
test code below: