├── README.md └── nmf.py /README.md: -------------------------------------------------------------------------------- 1 | # NMF-Tensorflow 2 | Non-negative Matrix Factorization (NMF) Tensorflow Implementation. 3 | 4 | 5 | ## Examples 6 | ``` 7 | >>> import numpy as np 8 | >>> from nmf import NMF 9 | >>> V = np.array([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]]) 10 | >>> model = NMF(max_iter=200,learning_rate=0.01,display_step=10, optimizer='mu') 11 | >>> W, H = model.fit_transform(V, r_components=2, initW=False, givenW=0) 12 | >>> print(V) 13 | >>> print(model.inverse_transform(W, H)) 14 | ``` 15 | 16 | ## Optimization 17 | - Gradient Descent with Multiplicative Update Rule 18 | - Projected Gradient 19 | 20 | ## TODO: 21 | - [ ] Sparse NMF 22 | - [ ] Discriminant NMF 23 | -------------------------------------------------------------------------------- /nmf.py: -------------------------------------------------------------------------------- 1 | """ Non-negative matrix factorization (tensorflow)""" 2 | # Author: Eesung Kim 3 | 4 | import numpy as np 5 | import tensorflow as tf 6 | 7 | class NMF: 8 | """Compute Non-negative Matrix Factorization (NMF)""" 9 | def __init__(self, max_iter=200, learning_rate=0.01,display_step=10, optimizer='mu', initW=False): 10 | 11 | self.max_iter = max_iter 12 | self.learning_rate= learning_rate 13 | self.display_step = display_step 14 | self.optimizer = optimizer 15 | 16 | def NMF(self, X, r_components, learning_rate, max_iter, display_step, optimizer, initW, givenW ): 17 | m,n=np.shape(X) 18 | tf.reset_default_graph() 19 | V = tf.placeholder(tf.float32) 20 | 21 | initializer = tf.random_uniform_initializer(0,1) 22 | if initW is False: 23 | W = tf.get_variable(name="W", shape=[m, r_components], initializer=initializer) 24 | H = tf.get_variable("H", [r_components, n], initializer=initializer) 25 | else: 26 | W = tf.constant(givenW, shape=[m, r_components], name="W") 27 | H = tf.get_variable("H", [r_components, n], initializer=initializer) 28 | 29 | WH =tf.matmul(W, H) 30 | cost = tf.reduce_sum(tf.square(V - WH)) 31 | 32 | if optimizer=='mu': 33 | """Compute Non-negative Matrix Factorization with Multiplicative Update""" 34 | Wt = tf.transpose(W) 35 | H_new = H * tf.matmul(Wt, V) / tf.matmul(tf.matmul(Wt, W), H) 36 | H_update = H.assign(H_new) 37 | 38 | if initW is False: 39 | Ht = tf.transpose(H) 40 | W_new = W * tf.matmul(V, Ht)/ tf.matmul(W, tf.matmul(H, Ht)) 41 | W_update = W.assign(W_new) 42 | 43 | elif optimizer=='pg': 44 | """optimization; Projected Gradient method """ 45 | dW, dH = tf.gradients(xs=[W, H], ys=cost) 46 | H_update_ = H.assign(H - learning_rate * dH) 47 | H_update = tf.where(tf.less(H_update_, 0), tf.zeros_like(H_update_), H_update_) 48 | 49 | if initW is False: 50 | W_update_ = W.assign(W - learning_rate * dW) 51 | W_update = tf.where(tf.less(W_update_, 0), tf.zeros_like(W_update_), W_update_) 52 | 53 | with tf.Session() as sess: 54 | sess.run(tf.global_variables_initializer()) 55 | for idx in range(max_iter): 56 | if initW is False: 57 | W=sess.run(W_update, feed_dict={V:X}) 58 | H=sess.run(H_update, feed_dict={V:X}) 59 | else: 60 | H=sess.run(H_update, feed_dict={V:X}) 61 | 62 | if (idx % display_step) == 0: 63 | costValue = sess.run(cost,feed_dict={V:X}) 64 | print("|Epoch:","{:4d}".format(idx), " Cost=","{:.3f}".format(costValue)) 65 | 66 | return W, H 67 | 68 | def fit_transform(self, X,r_components, initW, givenW): 69 | """Transform input data to W, H matrices which are the non-negative matrices.""" 70 | W, H = self.NMF(X=X, r_components = r_components, learning_rate=self.learning_rate, 71 | max_iter = self.max_iter, display_step = self.display_step, 72 | optimizer=self.optimizer, initW=initW, givenW=givenW ) 73 | return W, H 74 | 75 | def inverse_transform(self, W, H): 76 | """Transform data back to its original space.""" 77 | return np.matmul(W,H) 78 | 79 | def main(): 80 | V = np.array([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]]) 81 | model = NMF(max_iter=200,learning_rate=0.01,display_step=10, optimizer='mu') 82 | W, H = model.fit_transform(V, r_components=2, initW=False, givenW=0) 83 | print(W) 84 | print(H) 85 | print(V) 86 | print(model.inverse_transform(W, H)) 87 | 88 | if __name__ == '__main__': 89 | main() --------------------------------------------------------------------------------