scikit-learn/benchmarks/bench_plot_nmf.py

163 lines
5.5 KiB
Python
Raw Normal View History

2010-12-14 07:32:49 +08:00
"""
Benchmarks of Non-Negative Matrix Factorization
"""
2010-12-14 07:32:49 +08:00
import gc
from time import time
import numpy as np
from collections import defaultdict
2011-09-03 18:57:53 +08:00
from sklearn.decomposition.nmf import NMF, _initialize_nmf
from sklearn.datasets.samples_generator import make_low_rank_matrix
2010-12-14 07:32:49 +08:00
2011-04-02 03:04:15 +08:00
def alt_nnmf(V, r, max_iter=1000, tol=1e-3, R=None):
2010-12-14 07:32:49 +08:00
'''
A, S = nnmf(X, r, tol=1e-3, R=None)
2010-12-14 07:32:49 +08:00
Implement Lee & Seung's algorithm
Parameters
----------
2011-04-02 03:04:15 +08:00
V : 2-ndarray, [n_samples, n_features]
2010-12-14 07:32:49 +08:00
input matrix
r : integer
2011-04-02 03:06:19 +08:00
number of latent features
2010-12-14 07:32:49 +08:00
max_iter : integer, optional
maximum number of iterations (default: 10000)
tol : double
2011-04-02 03:04:15 +08:00
tolerance threshold for early exit (when the update factor is within
tol of 1., the function exits)
2010-12-14 07:32:49 +08:00
R : integer, optional
random seed
Returns
-------
2011-04-02 03:04:15 +08:00
A : 2-ndarray, [n_samples, r]
Component part of the factorization
2010-12-14 07:32:49 +08:00
2011-04-02 03:04:15 +08:00
S : 2-ndarray, [r, n_features]
Data part of the factorization
2010-12-14 07:32:49 +08:00
Reference
---------
"Algorithms for Non-negative Matrix Factorization"
by Daniel D Lee, Sebastian H Seung
(available at http://citeseer.ist.psu.edu/lee01algorithms.html)
'''
2011-04-02 03:48:03 +08:00
# Nomenclature in the function follows Lee & Seung
2010-12-14 07:32:49 +08:00
eps = 1e-5
2011-04-02 03:04:15 +08:00
n, m = V.shape
2010-12-14 07:32:49 +08:00
if R == "svd":
2011-05-02 16:25:09 +08:00
W, H = _initialize_nmf(V, r)
2010-12-14 07:32:49 +08:00
elif R == None:
R = np.random.mtrand._rand
2011-04-02 03:04:15 +08:00
W = np.abs(R.standard_normal((n, r)))
H = np.abs(R.standard_normal((r, m)))
2010-12-14 07:32:49 +08:00
for i in xrange(max_iter):
2011-04-02 03:04:15 +08:00
updateH = np.dot(W.T, V) / (np.dot(np.dot(W.T, W), H) + eps)
H *= updateH
updateW = np.dot(V, H.T) / (np.dot(W, np.dot(H, H.T)) + eps)
W *= updateW
2010-12-14 07:32:49 +08:00
if True or (i % 10) == 0:
2011-04-02 03:04:15 +08:00
max_update = max(updateW.max(), updateH.max())
if abs(1. - max_update) < tol:
2010-12-14 07:32:49 +08:00
break
return W, H
def compute_bench(samples_range, features_range, rank=50, tolerance=1e-7):
2010-12-14 07:32:49 +08:00
it = 0
timeset = defaultdict(lambda: [])
err = defaultdict(lambda: [])
max_it = len(samples_range) * len(features_range)
for n_samples in samples_range:
for n_features in features_range:
it += 1
print '===================='
print 'Iteration %03d of %03d' % (it, max_it)
print '===================='
X = np.abs(make_low_rank_matrix(n_samples, n_features,
effective_rank=rank, tail_strength=0.2))
2011-04-02 03:04:15 +08:00
2010-12-14 07:32:49 +08:00
gc.collect()
print "benching nndsvd-nmf: "
2010-12-14 07:32:49 +08:00
tstart = time()
m = NMF(n_components=30, tol=tolerance, init='nndsvd').fit(X)
tend = time() - tstart
timeset['nndsvd-nmf'].append(tend)
2011-04-02 04:34:35 +08:00
err['nndsvd-nmf'].append(m.reconstruction_err_)
print m.reconstruction_err_, tend
2011-04-02 04:34:35 +08:00
gc.collect()
print "benching nndsvda-nmf: "
tstart = time()
m = NMF(n_components=30, init='nndsvda',
2011-04-02 04:34:35 +08:00
tol=tolerance).fit(X)
tend = time() - tstart
timeset['nndsvda-nmf'].append(tend)
2011-04-02 04:34:35 +08:00
err['nndsvda-nmf'].append(m.reconstruction_err_)
print m.reconstruction_err_, tend
2011-04-02 04:34:35 +08:00
gc.collect()
print "benching nndsvdar-nmf: "
tstart = time()
m = NMF(n_components=30, init='nndsvdar',
2011-04-02 04:34:35 +08:00
tol=tolerance).fit(X)
tend = time() - tstart
timeset['nndsvdar-nmf'].append(tend)
2011-04-02 04:34:35 +08:00
err['nndsvdar-nmf'].append(m.reconstruction_err_)
print m.reconstruction_err_, tend
2010-12-14 07:32:49 +08:00
gc.collect()
print "benching random-nmf"
tstart = time()
m = NMF(n_components=30, init=None, max_iter=1000,
2011-04-02 03:04:15 +08:00
tol=tolerance).fit(X)
tend = time() - tstart
timeset['random-nmf'].append(tend)
2010-12-14 07:32:49 +08:00
err['random-nmf'].append(m.reconstruction_err_)
print m.reconstruction_err_, tend
2010-12-14 07:32:49 +08:00
gc.collect()
print "benching alt-random-nmf"
tstart = time()
W, H = alt_nnmf(X, r=30, R=None, tol=tolerance)
tend = time() - tstart
timeset['alt-random-nmf'].append(tend)
2011-04-02 03:04:15 +08:00
err['alt-random-nmf'].append(np.linalg.norm(X - np.dot(W, H)))
print np.linalg.norm(X - np.dot(W, H)), tend
2010-12-14 07:32:49 +08:00
return timeset, err
if __name__ == '__main__':
2011-04-02 03:04:15 +08:00
from mpl_toolkits.mplot3d import axes3d # register the 3d projection
2010-12-14 07:32:49 +08:00
import matplotlib.pyplot as plt
2011-04-02 05:04:10 +08:00
samples_range = np.linspace(50, 500, 3).astype(np.int)
features_range = np.linspace(50, 500, 3).astype(np.int)
2010-12-14 07:32:49 +08:00
timeset, err = compute_bench(samples_range, features_range)
2011-04-02 03:04:15 +08:00
for i, results in enumerate((timeset, err)):
2010-12-14 07:32:49 +08:00
fig = plt.figure()
ax = fig.gca(projection='3d')
2011-04-02 05:04:10 +08:00
for c, (label, timings) in zip('rbgcm', sorted(results.iteritems())):
2010-12-14 07:32:49 +08:00
X, Y = np.meshgrid(samples_range, features_range)
Z = np.asarray(timings).reshape(samples_range.shape[0],
features_range.shape[0])
# plot the actual surface
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3,
color=c)
# dummy point plot to stick the legend to since surface plot do not
# support legends (yet?)
ax.plot([1], [1], [1], color=c, label=label)
ax.set_xlabel('n_samples')
ax.set_ylabel('n_features')
zlabel = 'time (s)' if i == 0 else 'reconstruction error'
ax.set_zlabel(zlabel)
2010-12-14 07:32:49 +08:00
ax.legend()
plt.show()