annotate scripts/nmftools.py @ 105:edd82eb89b4b branch-tests tip

Merge
author Maria Panteli
date Sun, 15 Oct 2017 13:36:59 +0100
parents c4841876a8ff
children
rev   line source
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