m@9
|
1 # -*- coding: utf-8 -*-
|
m@9
|
2 """
|
m@9
|
3 Created on Wed Oct 26 12:46:13 2016
|
m@9
|
4
|
m@9
|
5 @author: https://github.com/keik/nmftools/blob/master/nmftools/core.py
|
m@9
|
6 """
|
m@9
|
7
|
m@9
|
8 import numpy as np
|
m@9
|
9
|
m@9
|
10
|
m@9
|
11 def nmf(Y, R=3, n_iter=50, init_H=[], init_U=[], verbose=False):
|
m@9
|
12 """
|
m@9
|
13 decompose non-negative matrix to components and activation with NMF
|
m@9
|
14 Y ≈ HU
|
m@9
|
15 Y ∈ R (m, n)
|
m@9
|
16 H ∈ R (m, k)
|
m@9
|
17 HU ∈ R (k, n)
|
m@9
|
18 parameters
|
m@9
|
19 ----
|
m@9
|
20 Y: target matrix to decompose
|
m@9
|
21 R: number of bases to decompose
|
m@9
|
22 n_iter: number for executing objective function to optimize
|
m@9
|
23 init_H: initial value of H matrix. default value is random matrix
|
m@9
|
24 init_U: initial value of U matrix. default value is random matrix
|
m@9
|
25 return
|
m@9
|
26 ----
|
m@9
|
27 Array of:
|
m@9
|
28 0: matrix of H
|
m@9
|
29 1: matrix of U
|
m@9
|
30 2: array of cost transition
|
m@9
|
31 """
|
m@9
|
32
|
m@9
|
33 eps = np.spacing(1)
|
m@9
|
34
|
m@9
|
35 # size of input spectrogram
|
m@9
|
36 M = Y.shape[0]
|
m@9
|
37 N = Y.shape[1]
|
m@9
|
38
|
m@9
|
39 # initialization
|
m@9
|
40 if len(init_U):
|
m@9
|
41 U = init_U
|
m@9
|
42 R = init_U.shape[0]
|
m@9
|
43 else:
|
m@9
|
44 U = np.random.rand(R,N);
|
m@9
|
45
|
m@9
|
46 if len(init_H):
|
m@9
|
47 H = init_H;
|
m@9
|
48 R = init_H.shape[1]
|
m@9
|
49 else:
|
m@9
|
50 H = np.random.rand(M,R)
|
m@9
|
51
|
m@9
|
52 # array to save the value of the euclid divergence
|
m@9
|
53 cost = np.zeros(n_iter)
|
m@9
|
54
|
m@9
|
55 # computation of Lambda (estimate of Y)
|
m@9
|
56 Lambda = np.dot(H, U)
|
m@9
|
57
|
m@9
|
58 # iterative computation
|
m@9
|
59 for i in range(n_iter):
|
m@9
|
60
|
m@9
|
61 # compute euclid divergence
|
m@9
|
62 cost[i] = euclid_divergence(Y, Lambda)
|
m@9
|
63
|
m@9
|
64 # update H
|
m@9
|
65 H *= np.dot(Y, U.T) / (np.dot(np.dot(H, U), U.T) + eps)
|
m@9
|
66
|
m@9
|
67 # update U
|
m@9
|
68 U *= np.dot(H.T, Y) / (np.dot(np.dot(H.T, H), U) + eps)
|
m@9
|
69
|
m@9
|
70 # recomputation of Lambda
|
m@9
|
71 Lambda = np.dot(H, U)
|
m@9
|
72
|
m@9
|
73 return [H, U, cost]
|
m@9
|
74
|
m@9
|
75
|
m@9
|
76 def ssnmf(Y, R=3, n_iter=50, F=[], init_G=[], init_H=[], init_U=[], verbose=False):
|
m@9
|
77 """
|
m@9
|
78 decompose non-negative matrix to components and activation with semi-supervised NMF
|
m@9
|
79 Y ≈ FG + HU
|
m@9
|
80 Y ∈ R (m, n)
|
m@9
|
81 F ∈ R (m, x)
|
m@9
|
82 G ∈ R (x, n)
|
m@9
|
83 H ∈ R (m, k)
|
m@9
|
84 U ∈ R (k, n)
|
m@9
|
85 parameters
|
m@9
|
86 ----
|
m@9
|
87 Y: target matrix to decompose
|
m@9
|
88 R: number of bases to decompose
|
m@9
|
89 n_iter: number for executing objective function to optimize
|
m@9
|
90 F: matrix as supervised base components
|
m@9
|
91 init_W: initial value of W matrix. default value is random matrix
|
m@9
|
92 init_H: initial value of W matrix. default value is random matrix
|
m@9
|
93 return
|
m@9
|
94 ----
|
m@9
|
95 Array of:
|
m@9
|
96 0: matrix of F
|
m@9
|
97 1: matrix of G
|
m@9
|
98 2: matrix of H
|
m@9
|
99 3: matrix of U
|
m@9
|
100 4: array of cost transition
|
m@9
|
101 """
|
m@9
|
102
|
m@9
|
103 eps = np.spacing(1)
|
m@9
|
104
|
m@9
|
105 # size of input spectrogram
|
m@9
|
106 M = Y.shape[0];
|
m@9
|
107 N = Y.shape[1];
|
m@9
|
108 X = F.shape[1]
|
m@9
|
109
|
m@9
|
110 # initialization
|
m@9
|
111 if len(init_G):
|
m@9
|
112 G = init_G
|
m@9
|
113 X = init_G.shape[1]
|
m@9
|
114 else:
|
m@9
|
115 G = np.random.rand(X, N)
|
m@9
|
116
|
m@9
|
117 if len(init_U):
|
m@9
|
118 U = init_U
|
m@9
|
119 R = init_U.shape[0]
|
m@9
|
120 else:
|
m@9
|
121 U = np.random.rand(R, N)
|
m@9
|
122
|
m@9
|
123 if len(init_H):
|
m@9
|
124 H = init_H
|
m@9
|
125 R = init_H.shape[1]
|
m@9
|
126 else:
|
m@9
|
127 H = np.random.rand(M, R)
|
m@9
|
128
|
m@9
|
129 # array to save the value of the euclid divergence
|
m@9
|
130 cost = np.zeros(n_iter)
|
m@9
|
131
|
m@9
|
132 # computation of Lambda (estimate of Y)
|
m@9
|
133 Lambda = np.dot(F, G) + np.dot(H, U)
|
m@9
|
134
|
m@9
|
135 # iterative computation
|
m@9
|
136 for it in range(n_iter):
|
m@9
|
137
|
m@9
|
138 # compute euclid divergence
|
m@9
|
139 cost[it] = euclid_divergence(Y, Lambda + eps)
|
m@9
|
140
|
m@9
|
141 # update of H
|
m@9
|
142 H *= (np.dot(Y, U.T) + eps) / (np.dot(np.dot(H, U) + np.dot(F, G), U.T) + eps)
|
m@9
|
143
|
m@9
|
144 # update of U
|
m@9
|
145 U *= (np.dot(H.T, Y) + eps) / (np.dot(H.T, np.dot(H, U) + np.dot(F, G)) + eps)
|
m@9
|
146
|
m@9
|
147 # update of G
|
m@9
|
148 G *= (np.dot(F.T, Y) + eps)[np.arange(G.shape[0])] / (np.dot(F.T, np.dot(H, U) + np.dot(F, G)) + eps)
|
m@9
|
149
|
m@9
|
150 # recomputation of Lambda (estimate of V)
|
m@9
|
151 Lambda = np.dot(H, U) + np.dot(F, G)
|
m@9
|
152
|
m@9
|
153 return [F, G, H, U, cost]
|
m@9
|
154
|
m@9
|
155
|
m@9
|
156 def euclid_divergence(V, Vh):
|
m@9
|
157 d = 1 / 2 * (V ** 2 + Vh ** 2 - 2 * V * Vh).sum()
|
m@9
|
158 return d |