我試圖使用Kullback-Liebler分歧作爲相似性度量來實現非負矩陣分解。該算法描述如下:http://hebb.mit.edu/people/seung/papers/nmfconverge.pdf。下面是我的python/numpy實現,用一個示例矩陣來運行它。簡而言之,該算法應該學習矩陣W(n by r)和H(r by m),使得V(n乘m)近似爲WH。從W和H中的隨機值開始,按照Seung和Lee論文中描述的更新規則,您應該更接近W和H的近似值。非負矩陣分解未能收斂
該算法已被證明單調地減少分歧度量,但這不是我的實現中發生的情況。相反,它會解決兩個分歧值之間的交替。如果你看W和H,你可以看到由此產生的因子不是特別好。
我想知道在計算W的更新時是否使用更新的或舊的H。我試過這兩種方法,並且它不會改變實現的行爲。
我已經檢查了我的實施對紙張一堆,我看不到我做錯了什麼。任何人都可以解釋一下這個問題嗎?
import numpy as np
def update(V, W, H, r, n, m):
n,m = V.shape
WH = W.dot(H)
# equation (5)
H_coeff = np.zeros(H.shape)
for a in range(r):
for mu in range(m):
for i in range(n):
H_coeff[a, mu] += W[i, a] * V[i, mu]/WH[i, mu]
H_coeff[a, mu] /= sum(W)[a]
H = H * H_coeff
W_coeff = np.zeros(W.shape)
for i in range(n):
for a in range(r):
for mu in range(m):
W_coeff[i, a] += H[a, mu] * V[i, mu]/WH[i, mu]
W_coeff[i, a] /= sum(H.T)[a]
W = W * W_coeff
return W, H
def factor(V, r, iterations=100):
n, m = V.shape
avg_V = sum(sum(V))/n/m
W = np.random.random(n*r).reshape(n,r)*avg_V
H = np.random.random(r*m).reshape(r,m)*avg_V
for i in range(iterations):
WH = W.dot(H)
divergence = sum(sum(V * np.log(V/WH) - V + WH)) # equation (3)
print "At iteration " + str(i) + ", the Kullback-Liebler divergence is", divergence
W,H = update(V, W, H, r, n, m)
return W, H
V = np.arange(0.01,1.01,0.01).reshape(10,10)
W, H = factor(V, 6)
是的,你說得對,重新計算WH = W.dot(H)消除了交替效應。其餘的評論也非常有幫助。我很感激你的詳細和明確的迴應。 –
Aargh。我也一直在研究這一點,並得出了類似的結論。應該有更好的瞭解。 ; ^)唯一值得添加的是'einsum'版本,例如'H_coeff = np.einsum('ia,im,im-> am',W,V,1.0/W.dot(H))/ W.sum(axis = 0,keepdims = True)。 H = H * H_coeff; W_coeff = np.einsum('am,im,im-> ia',H,V,1.0/W.dot(H))/ H.sum(axis = 1,keepdims = True)。 W = W * W_coeff',理由是'einsum'確實可以用來確認你輸入的公式與寫入的公式相同。 – DSM
@DSM:謝謝你的支持。我需要更熟悉'np.einsum'。 – unutbu