Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 48 additions & 48 deletions sklearn/decomposition/_nmf.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,100 +627,100 @@ def _multiplicative_update_w(


def _multiplicative_update_h(
X, W, H, beta_loss, l1_reg_H, l2_reg_H, gamma, A=None, B=None, rho=None
X, w, h, beta_loss, l1_reg_h, l2_reg_h, gamma, a=None, b=None, rho=None
):
"""update H in Multiplicative Update NMF."""
if beta_loss == 2:
numerator = safe_sparse_dot(W.T, X)
denominator = np.linalg.multi_dot([W.T, W, H])
numerator = safe_sparse_dot(w.T, X)
denominator = np.linalg.multi_dot([w.T, w, h])

else:
# Numerator
WH_safe_X = _special_sparse_dot(W, H, X)
wh_safe_x = _special_sparse_dot(w, h, X)
if sp.issparse(X):
WH_safe_X_data = WH_safe_X.data
X_data = X.data
wh_safe_x_data = wh_safe_x.data
x_data = X.data
else:
WH_safe_X_data = WH_safe_X
X_data = X
wh_safe_x_data = wh_safe_x
x_data = X
# copy used in the Denominator
WH = WH_safe_X.copy()
WH = wh_safe_x.copy()
if beta_loss - 1.0 < 0:
WH[WH < EPSILON] = EPSILON

# to avoid division by zero
if beta_loss - 2.0 < 0:
WH_safe_X_data[WH_safe_X_data < EPSILON] = EPSILON
wh_safe_x_data[wh_safe_x_data < EPSILON] = EPSILON

if beta_loss == 1:
np.divide(X_data, WH_safe_X_data, out=WH_safe_X_data)
np.divide(x_data, wh_safe_x_data, out=wh_safe_x_data)
elif beta_loss == 0:
# speeds up computation time
# refer to /numpy/numpy/issues/9363
WH_safe_X_data **= -1
WH_safe_X_data **= 2
wh_safe_x_data **= -1
wh_safe_x_data **= 2
# element-wise multiplication
WH_safe_X_data *= X_data
wh_safe_x_data *= x_data
else:
WH_safe_X_data **= beta_loss - 2
wh_safe_x_data **= beta_loss - 2
# element-wise multiplication
WH_safe_X_data *= X_data
wh_safe_x_data *= x_data

# here numerator = dot(W.T, (dot(W, H) ** (beta_loss - 2)) * X)
numerator = safe_sparse_dot(W.T, WH_safe_X)
numerator = safe_sparse_dot(w.T, wh_safe_x)

# Denominator
if beta_loss == 1:
W_sum = np.sum(W, axis=0) # shape(n_components, )
W_sum[W_sum == 0] = 1.0
denominator = W_sum[:, np.newaxis]
w_sum = np.sum(w, axis=0) # shape(n_components, )
w_sum[w_sum == 0] = 1.0
denominator = w_sum[:, np.newaxis]

# beta_loss not in (1, 2)
else:
# computation of WtWH = dot(W.T, dot(W, H) ** beta_loss - 1)
if sp.issparse(X):
# memory efficient computation
# (compute column by column, avoiding the dense matrix WH)
WtWH = np.empty(H.shape)
WtWH = np.empty(h.shape)
for i in range(X.shape[1]):
WHi = np.dot(W, H[:, i])
WHi = np.dot(w, h[:, i])
if beta_loss - 1 < 0:
WHi[WHi < EPSILON] = EPSILON
WHi **= beta_loss - 1
WtWH[:, i] = np.dot(W.T, WHi)
WtWH[:, i] = np.dot(w.T, WHi)
else:
WH **= beta_loss - 1
WtWH = np.dot(W.T, WH)
WtWH = np.dot(w.T, WH)
denominator = WtWH

# Add L1 and L2 regularization
if l1_reg_H > 0:
denominator += l1_reg_H
if l2_reg_H > 0:
denominator = denominator + l2_reg_H * H
if l1_reg_h > 0:
denominator += l1_reg_h
if l2_reg_h > 0:
denominator = denominator + l2_reg_h * h
denominator[denominator == 0] = EPSILON

if A is not None and B is not None:
if a is not None and b is not None:
# Updates for the online nmf
if gamma != 1:
H **= 1 / gamma
numerator *= H
A *= rho
B *= rho
A += numerator
B += denominator
H = A / B
h **= 1 / gamma
numerator *= h
a *= rho
b *= rho
a += numerator
b += denominator
h = a / b

if gamma != 1:
H **= gamma
h **= gamma
else:
delta_H = numerator
delta_H /= denominator
delta_h = numerator
delta_h /= denominator
if gamma != 1:
delta_H **= gamma
H *= delta_H
delta_h **= gamma
h *= delta_h

return H
return h


def _fit_multiplicative_update(
Expand Down Expand Up @@ -851,8 +851,8 @@ def _fit_multiplicative_update(
W,
H,
beta_loss=beta_loss,
l1_reg_H=l1_reg_H,
l2_reg_H=l2_reg_H,
l1_reg_h=l1_reg_H,
l2_reg_h=l2_reg_H,
gamma=gamma,
)

Expand Down Expand Up @@ -2100,11 +2100,11 @@ def _minibatch_step(self, X, W, H, update_H):
W,
H,
beta_loss=self._beta_loss,
l1_reg_H=l1_reg_H,
l2_reg_H=l2_reg_H,
l1_reg_h=l1_reg_H,
l2_reg_h=l2_reg_H,
gamma=self._gamma,
A=self._components_numerator,
B=self._components_denominator,
a=self._components_numerator,
b=self._components_denominator,
rho=self._rho,
)

Expand Down
Loading