梯度下降:
import math
import random as rd
def Loss(U, I, D, d):
loss = 0
for u, i in D:
loss += pow(sum([U[u][t]*I[i][t] for t in range(d)])-D[u, i], 2)
return loss
def step_search(U, dU, I, dI, x, d, D):
U1 = {u: [U[u][t] + x * dU[u][t] for t in range(d)] for u in U}
I1 = {i: [I[i][t] + x * dI[i][t] for t in range(d)] for i in I}
return Loss(U1, I1, D, d)
def mod(dU, dI, d):
return math.sqrt(sum([dU[u][t]*dU[u][t] for u in dU for t in range(d)])+sum([dI[i][t]*dI[i][t] for i in dI for t in range(d)]))
def Matrix_Decomposition(users, items, M, d, r=0.8, step_min=0.00001):
U = {u: [rd.random() for t in range(d)] for u in users}
I = {i: [rd.random() for t in range(d)] for i in items}
D = {(row[0], row[1]): row[2] for row in M}
loop = 0
while True:
loop += 1
print("loop: ", loop, "loss: ", Loss(U, I, D, d))
#负梯度方向
dU = {u:[-2*sum([(sum([U[u][t1]*I[i][t1] for t1 in range(d)])-D[u, i])*I[i][t] for i in I if (u, i) in D]) for t in range(d)] for u in U}
dI = {i:[-2*sum([(sum([U[u][t1]*I[i][t1] for t1 in range(d)])-D[u, i])*U[u][t] for u in U if (u, i) in D]) for t in range(d)] for i in I}
left = 0
right = 1
while step_search(U, dU, I, dI, right, d, D) < step_search(U, dU, I, dI, 0, d, D):
right = right * (2 - r)
mid1 = left * 2 / 3 + right / 3
mid2 = left / 3 + right * 2 / 3
while abs(left - right) * mod(dU, dI, d) > step_min:
if step_search(U, dU, I, dI, mid1, d, D) < step_search(U, dU, I, dI, mid2, d, D):
right = mid2
else:
left = mid1
mid1 = left * 2 / 3 + right / 3
mid2 = left / 3 + right * 2 / 3
if left * mod(dU, dI, d) < step_min:
break
U = {u: [U[u][t] + left * dU[u][t] for t in range(d)] for u in U}
I = {i: [I[i][t] + left * dI[i][t] for t in range(d)] for i in I}
print("loop: ", loop, "loss: ", Loss(U, I, D, d))
return U, I
if __name__ == '__main__':
users = [1,2,3]
items = [1, 2, 3]
M = [[1, 1, 1],
[2, 1, 0],
[3, 1, 0],
[1, 2, 0],
[2, 2, 1],
[3, 2, 0],
[1, 3, 0],
[2, 3, 0],
[3, 3, 1]]
d = 4
U, I = Matrix_Decomposition(users, items, M, d)
SGD:
import math
import random as rd
def Loss(U, I, D, d):
loss = 0
for u, i in D:
loss += pow(sum([U[u][t]*I[i][t] for t in range(d)])-D[u, i], 2)
return loss
def step_search(U, dU, I, dI, x, d, D):
U1 = {u: [U[u][t] + x * dU[u][t] for t in range(d)] for u in U}
I1 = {i: [I[i][t] + x * dI[i][t] for t in range(d)] for i in I}
return Loss(U1, I1, D, d)
def mod(dU, dI, d):
return math.sqrt(sum([dU[u][t]*dU[u][t] for u in dU for t in range(d)])+sum([dI[i][t]*dI[i][t] for i in dI for t in range(d)]))
def Matrix_Decomposition(users, items, M, d, r=0.8, step_min=0.00001, s=0.1):
U = {u: [rd.random() for t in range(d)] for u in users}
I = {i: [rd.random() for t in range(d)] for i in items}
D = {(row[0], row[1]): row[2] for row in M}
loop = 0
while True:
loop += 1
z0 = Loss(U, I, D, d)
print("loop: ", loop, "z0: ", z0)
for u, i in D:
du = [-2*(sum([U[u][t1]*I[i][t1] for t1 in range(d)])-D[u, i])*I[i][t] for t in range(d)]
di = [-2*(sum([U[u][t1]*I[i][t1] for t1 in range(d)])-D[u, i])*U[u][t] for t in range(d)]
u1 = [U[u][t]+s*du[t] for t in range(d)]
i1 = [I[i][t]+s*di[t] for t in range(d)]
U[u] = u1
I[i] = i1
z1 = Loss(U, I, D, d)
print("loop: ", loop, "z1: ", z1)
if abs(z1-z0) < step_min:
break
print("loop: ", loop, "loss: ", Loss(U, I, D, d))
return U, I
if __name__ == '__main__':
users = [1,2,3]
items = [1, 2, 3]
M = [[1, 1, 1],
[2, 1, 0],
[3, 1, 0],
[1, 2, 0],
[2, 2, 1],
[3, 2, 0],
[1, 3, 0],
[2, 3, 0],
[3, 3, 1]]
d = 4
U, I = Matrix_Decomposition(users, items, M, d)
固定步长:
import math
import random as rd
def Loss(U, I, D, d):
loss = 0
for u, i in D:
loss += pow(sum([U[u][t]*I[i][t] for t in range(d)])-D[u, i], 2)
return loss
def step_search(U, dU, I, dI, x, d, D):
U1 = {u: [U[u][t] + x * dU[u][t] for t in range(d)] for u in U}
I1 = {i: [I[i][t] + x * dI[i][t] for t in range(d)] for i in I}
return Loss(U1, I1, D, d)
def mod(dU, dI, d):
return math.sqrt(sum([dU[u][t]*dU[u][t] for u in dU for t in range(d)])+sum([dI[i][t]*dI[i][t] for i in dI for t in range(d)]))
def Matrix_Decomposition(users, items, M, d, r=0.8, step_min=0.00001):
U = {u: [rd.random() for t in range(d)] for u in users}
I = {i: [rd.random() for t in range(d)] for i in items}
D = {(row[0], row[1]): row[2] for row in M}
loop = 0
while True:
loop += 1
print("loop: ", loop, "loss: ", Loss(U, I, D, d))
#负梯度方向
dU = {u:[-2*sum([(sum([U[u][t1]*I[i][t1] for t1 in range(d)])-D[u, i])*I[i][t] for i in I if (u, i) in D]) for t in range(d)] for u in U}
dI = {i:[-2*sum([(sum([U[u][t1]*I[i][t1] for t1 in range(d)])-D[u, i])*U[u][t] for u in U if (u, i) in D]) for t in range(d)] for i in I}
left = 0.1
if left * mod(dU, dI, d) < step_min:
break
U = {u: [U[u][t] + left * dU[u][t] for t in range(d)] for u in U}
I = {i: [I[i][t] + left * dI[i][t] for t in range(d)] for i in I}
print("loop: ", loop, "loss: ", Loss(U, I, D, d))
return U, I
if __name__ == '__main__':
users = [1,2,3]
items = [1, 2, 3]
M = [[1, 1, 1],
[2, 1, 0],
[3, 1, 0],
[1, 2, 0],
[2, 2, 1],
[3, 2, 0],
[1, 3, 0],
[2, 3, 0],
[3, 3, 1]]
d = 4
U, I = Matrix_Decomposition(users, items, M, d)