我一直试图在数据集上使用分解机器(http://www.algo.uni-konstanz.de/members/rendle/pdf/Rendle2010FM.pdf)来解决分类问题(ERROR VS NO ERROR),使用随机梯度下降作为学习方法。 我试图将它用于非常稀疏的矩阵(1000列,仅1-0,大约90%的条目值为0)。
事情并没有真正起作用:当我尝试将我的代码应用于testing_set时,V和w在此过程中几乎是不变的。没有任何变化或趋同或任何变化。 结果是,最终,我得到了一个预测数据,其中绝对没有检测到错误 我的第一个猜测是,可能是因为我的数据非常不平衡(10%的错误),所以我根据这个改变了我的训练集,现在我已经获得了14000的训练集7000个错误的行。仍然没有改变一件事!
我整天都在努力去看我错在哪里,但我似乎无法找到它。我试过了'ypred'和' grad_hinge'关于V,w的非常具体的值,在纸上做了数学计算,它们似乎都很好用 SDG只使用这两个功能,在我看来,与理论上的SDG相比,实现是好的(http://cs229.stanford.edu/notes/cs229-notes1.pdf,第7页)。
这是我的代码:
def ypred(V,w,x):
j=0
x2=[nb*nb for nb in x]
for f in range (V.shape[1]):
v2=[nb*nb for nb in V[:,f]]
j+=np.dot(x,V[:,f])**2-np.dot(x2,v2)
return w[0]+np.dot(w[1:],x)+0.5*j
第一个是Rendle的文章(第2页和第3页)中介绍的y_hat。我用
进行了测试Vtest=np.array([[0.5,3,4],[5,1,0],[8,1,2],[9,-4,5]])
wtest=np.array([0.5,0.3,2,4,0.8])
xtest=np.array([1,4,6,2])
y_main=0.5+(0.3+8+24+1.6)+0.5*((0.5+20+48+18)**2-(0.25+400+1728+324)+(3+4+6-8)**2-(9+16+36+64)+26**2-(16+144+60))
ypred(Vtest,wtest,xtest)
我得到 y_pred = 2914.4 ,这是个好结果。
def grad_hinge(V,w,x,y):
Jv=np.zeros(V.shape)
Jw=np.zeros(len(w))
y_hat=ypred(V,w,x)
c=y*y_hat
Jw[0]= 0 if c > 1 else -y
for i in range (1,len(w)):
Jw[i]= 0 if c > 1 else -y*x[i-1]
for i in range (V.shape[0]):
for k in range (V.shape[1]):
Jv[i,k]=0 if c > 1 else -y*(x[i]*np.dot(V[:,k],x)-V[i,k]*(x[i]**2))
return Jw,Jv
grad_hinge用于铰链损耗梯度。有两类参数(w_i和v_ {i,j}),这就是我引入Jw和Jv的原因。经测试:
Vtest=np.array([[0.5,3],[5,1],[-2,1],[1,-4]])
wtest=np.array([0.5,0.3,2,4,0.8])
xtest=np.array([1,0,0,1])
y=1
print(ypred(Vtest,wtest,xtest))
print(grad_hinge(Vtest,wtest,xtest,y))
返回 w = [ - 1,-1,0,0,-1] 和 V = [[ - 1,4],[0,0],[0 ,0],[ - 0.5,-3]] ,这是预期的结果。
def SDG(V,w,X,Y,a,c,niter):
delta1, delta2, epoch = [100],[100], 0
while ((norm(delta1, np.inf) >c or norm(delta2, np.inf)>c) and epoch < niter) :
for i in range (X.shape[0]):
print(i*100/X.shape[0])
Jw,Jv=grad_hinge(V,w,X[i],Y[i])
w1=np.array([w[j]-a*Jw[j] for j in range(len(w))])
V1=np.zeros(V.shape)
for i in range (V.shape[0]):
V1[i]=[V[i,k] - a*Jv[i,k] for k in range (V.shape[1])]
delta1=w1-w
delta2=V1-V
w,V=w1,V1
epoch+=1
print(epoch)
return w,V
在这里,我尝试按照Andrew Ng的课程(在那里链接)中的描述实现SGD。
有人能告诉我在我的代码中我可能有缺陷吗? 谢谢 !