muem.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import numpy as np
  2. import time
  3. def muem(data, G, F, r, Tmax):
  4. delta_measure = 1
  5. iter_max = round(Tmax / delta_measure) + 1
  6. T = np.empty(shape=(iter_max + 1))
  7. T.fill(np.nan)
  8. RMSE = np.empty(shape=(2, iter_max + 1))
  9. RMSE.fill(np.nan)
  10. mu_rate = 0.05
  11. mu_res = mu(data, G, F, r, mu_rate * Tmax, T, RMSE, delta_measure)
  12. return em(data, mu_res['G'], mu_res['F'], r, (1 - mu_rate) * Tmax, mu_res['T'], mu_res['RMSE'], mu_res['mu_state'], delta_measure)
  13. def mu(data, G, F, r, Tmax, T, RMSE, delta_measure):
  14. W2 = np.square(data.W)
  15. secu = 1e-12
  16. # RRE = np.empty(shape=(iter_max + 1))
  17. # RRE.fill(np.nan)
  18. delta_G = G
  19. delta_F = F
  20. t = time.time()
  21. T[0] = time.time() - t
  22. RMSE[:, 0] = np.linalg.norm(F[:, 0:-1] - data.F[:, 0:-1], 2, axis=1) / np.sqrt(F.shape[1] - 1)
  23. i = 0
  24. while time.time() - t <= Tmax + delta_measure:
  25. # Updating G
  26. np.put(delta_G, data.idxOG, 0)
  27. delta_G = np.divide(
  28. np.multiply(
  29. delta_G,
  30. np.dot(
  31. np.multiply(
  32. W2,
  33. secu_plus(data.X - data.Phi_G.dot(F), secu)
  34. ),
  35. F.T
  36. )
  37. ),
  38. np.dot(
  39. np.multiply(
  40. W2,
  41. delta_G.dot(F)
  42. ),
  43. F.T
  44. )
  45. )
  46. delta_G[np.isnan(delta_G)] = 0
  47. G = delta_G
  48. np.put(G, data.idxOG, data.sparsePhi_G)
  49. # Updating F
  50. np.put(F, data.idxOF, 0)
  51. delta_F = np.divide(
  52. np.multiply(
  53. delta_F,
  54. np.dot(
  55. G.T,
  56. np.multiply(
  57. W2,
  58. secu_plus(data.X - G.dot(data.Phi_F), secu)
  59. )
  60. )
  61. ),
  62. np.dot(
  63. G.T,
  64. np.multiply(
  65. W2,
  66. G.dot(delta_F)
  67. )
  68. )
  69. )
  70. delta_F[np.isnan(delta_F)] = 0
  71. F = delta_F
  72. np.put(F, data.idxOF, data.sparsePhi_F)
  73. # Saving results for this iteration
  74. if time.time() - t - i * delta_measure >= delta_measure:
  75. i = i + 1
  76. RMSE[:, i] = np.linalg.norm(F[:, 0:-1] - data.F[:, 0:-1], 2, axis=1) / np.sqrt(F.shape[1] - 1)
  77. T[i] = time.time() - t
  78. return {'G': G, 'F': F, 'T': T, 'RMSE': RMSE, 'mu_state': i}
  79. def secu_plus(tutu, s):
  80. toto = np.maximum(tutu, s)
  81. toto[np.isnan(tutu)] = 0
  82. return toto
  83. def em(data, G, F, r, Tmax, T, RMSE, mu_state, delta_measure):
  84. tol = 1e-5
  85. em_iter_max = round(Tmax / delta_measure) + 1 #
  86. M_loop = 5 # Number of passage over M step
  87. ITER_MAX = 3 # maximum inner iteration number (Default)
  88. ITER_MIN = 1 # minimum inner iteration number (Default)
  89. np.put(F, data.idxOF, data.sparsePhi_F)
  90. np.put(G, data.idxOG, data.sparsePhi_G)
  91. X = data.X + np.multiply(data.nW, np.dot(G, F))
  92. FXt = np.dot(F, X.T)
  93. FFt = np.dot(F, F.T)
  94. GtX = np.dot(G.T, X)
  95. GtG = np.dot(G.T, G)
  96. tolF = tol * stop_rule(F, np.dot(GtG, F) - GtX)
  97. tolG = tol * stop_rule(G.T, (np.dot(G, FFt) - FXt.T).T) # Stopping tolerance
  98. # Iterative updating
  99. G = G.T
  100. k = mu_state
  101. t = time.time()
  102. # Main loop
  103. while time.time() - t <= Tmax + delta_measure:
  104. # Estimation step
  105. X = data.X + np.multiply(data.nW, np.dot(G.T, F))
  106. # Maximisation step
  107. for _ in range(M_loop):
  108. # Optimize F with fixed G
  109. np.put(F, data.idxOF, 0)
  110. F, iterF, _ = NNLS(F, GtG, GtX - GtG.dot(data.Phi_F), ITER_MIN, ITER_MAX, tolF, data.idxOF, False)
  111. np.put(F, data.idxOF, data.sparsePhi_F)
  112. # print(F[:,0:5])
  113. if iterF <= ITER_MIN:
  114. tolF = tolF / 10
  115. # print('Tweaked F tolerance to '+str(tolF))
  116. FFt = np.dot(F, F.T)
  117. FXt = np.dot(F, X.T)
  118. # Optimize G with fixed F
  119. np.put(G.T, data.idxOG, 0)
  120. G, iterG, _ = NNLS(G, FFt, FXt - FFt.dot(data.Phi_G.T), ITER_MIN, ITER_MAX, tolG, data.idxOG, True)
  121. np.put(G.T, data.idxOG, data.sparsePhi_G)
  122. if iterG <= ITER_MIN:
  123. tolG = tolG / 10
  124. # print('Tweaked G tolerance to '+str(tolG))
  125. GtG = np.dot(G, G.T)
  126. GtX = np.dot(G, X)
  127. if time.time() - t - (k-mu_state) * delta_measure >= delta_measure:
  128. k = k + 1
  129. if (k-mu_state) >= em_iter_max:
  130. break
  131. RMSE[:, k] = np.linalg.norm(F[:, 0:-1] - data.F[:, 0:-1], 2, axis=1) / np.sqrt(F.shape[1] - 1)
  132. T[k] = T[mu_state] + time.time() - t
  133. return {'RMSE': RMSE, 'T': T}
  134. def stop_rule(X, GradX):
  135. # Stopping Criterions
  136. pGrad = GradX[np.any(np.dstack((X > 0, GradX < 0)), 2)]
  137. return np.linalg.norm(pGrad, 2)
  138. def NNLS(Z, GtG, GtX, iterMin, iterMax, tol, idxfixed, transposed):
  139. L = np.linalg.norm(GtG, 2) # Lipschitz constant
  140. H = Z # Initialization
  141. Grad = np.dot(GtG, Z) - GtX # Gradient
  142. alpha1 = 1
  143. for iter in range(1, iterMax + 1):
  144. H0 = H
  145. H = np.maximum(Z - Grad / L, 0) # Calculate squence 'Y'
  146. if transposed: # If Z = G.T
  147. np.put(H.T, idxfixed, 0)
  148. else: # If Z = F
  149. np.put(H, idxfixed, 0)
  150. alpha2 = 0.5 * (1 + np.sqrt(1 + 4 * alpha1 ** 2))
  151. Z = H + ((alpha1 - 1) / alpha2) * (H - H0)
  152. alpha1 = alpha2
  153. Grad = np.dot(GtG, Z) - GtX
  154. # Stopping criteria
  155. if iter >= iterMin:
  156. # Lin's stopping criteria
  157. pgn = stop_rule(Z, Grad)
  158. if pgn <= tol:
  159. break
  160. return H, iter, Grad
  161. def nmf_norm_fro(X, G, F, *args):
  162. W = args
  163. if len(W) == 0:
  164. f = np.square(np.linalg.norm(X - np.dot(G, F), 'fro')) / np.square(np.linalg.norm(X, 'fro'))
  165. else:
  166. W = W[0]
  167. f = np.square(np.linalg.norm(X - np.multiply(W, np.dot(G, F)), 'fro')) / np.square(np.linalg.norm(X, 'fro'))
  168. return f