我正在实现一种机器学习算法,该算法将矩阵近似为其他两个矩阵的倍数:V〜= WH。 W和H是随机初始化的,并且会进行迭代更新,以使WH更类似于V。
在我的代码中,每次迭代时,我要(i)更新W和H,以及(ii)根据W和H的新值计算分数。
我的问题是这样的:我用来评分的函数只能计算一个评分-不应影响 V,W或H,但看来确实可以!我不知道为什么函数会影响全局变量-我认为只有在您声明global foo
形式的情况下才会发生这种情况。结果是差异很小根据每次迭代是否计算分数,计算得出的W和H中的值-这没有意义。
下面是一些我已尽可能简化的代码-它没有实现我的算法或没有做任何有意义的事情,只是重现了问题,即根据您是否评论,计算出的W会有微小差异计算分数的线。
谁能看到为什么这会改变结果?
import numpy as np
# TRUE, GLOBAL VALUE OF V - should remain the same throughout
V = np.array([[0.0, 4.0, 0.0, 4.0],
[0.0, 0.0, 1.0, 0.0],
[4.0, 0.0, 0.0, 3.0]]).astype(float)
# RANDOM INITIALIZATIONS for two matrices, which are then updated by later steps
W = np.array([[ 1.03796229, 1.29098839],
[ 0.49131664, 0.79759996],
[ 0.66055735, 0.48055734]]).astype(float)
H = np.array([[ 0.06923306, 0.53105902, 1.1715193, 0.58126684],
[ 1.71226543, 0.54797385, 0.70978869, 1.58761463]]).astype(float)
# A small number, which is added at some steps to prevent zero division errors/overflows
min_no = np.finfo(np.float32).eps
# A function which calculates SOME SCORE based on V_input - below is the simplest example that reproduces the error
# This function should ONLY calculate and return a score - IT SHOULD NOT UPDATE GLOBAL VARIABLES!
def score(V_input):
V_input[V_input == 0] = min_no # I believe that THIS LINE may be UPDATING GLOBAL V - but I don't understand why
scr = np.sum(V_input)
return scr
# This function UPDATES the W matrix
def W_update(Vw, Ww, Hw):
WHw = np.matmul(Ww, Hw)
WHw[WHw == 0] = min_no
ratio = np.matmul(np.divide(Vw, WHw), np.transpose(Hw))
return np.multiply(Ww, ratio)
# Repeated update steps
for it in range(10):
# Update step
W = W_update(V, W, H)
# SCORING STEP - A SCORE IS CALCULATED - SHOULD NOT UPDATE GLOBAL VARIABLES
# HOWEVER, IT APPEARS TO DO SO - SMALL DIFFERENCES BETWEEN FINAL W WHEN COMMENTED OUT/NOT COMMENTED OUT
score_after_iteration = score(V)
# THE OUTPUT PRINTED HERE IS DIFFERENT DEPENDING ON WHETHER OR NOT THE SCORING STEP IS COMMENTED OUT - WHY?
print(W[:2,:2]) # Just a sample from W after last iteration
答案 0 :(得分:3)
如果传递变量,则将 reference 传递给该对象。因此,如果您使用V
调用函数,则会传递对矩阵V
的引用,因此对矩阵的更新就是对该对象的编辑。例如,如果您传递对该列表的引用,然后该函数编辑该列表,则您不编辑该列表的副本,但是列表本身,因此这些更改可以在外部看到电话。
不过,您可以进行复制,例如:
for it in range(10):
# Update step
W = W_update(V, W, H)
score_after_iteration = score(V.copy())
顺便说一句,W_update
也是如此,但这可能不是问题。
答案 1 :(得分:2)
或者,更改您的score
函数以不更新其任何输入:
def score(V_input):
return np.sum(np.where(V_input == 0, min_no, V_input))