利用矩阵,梯度下降算法实现的因子分解机
import numpy as np
LEARNING_RATE = 0.95 REGULARIZATION_COEFFICIENT = 0.000001 STEP_THRESHOLD = 300 K = 6
def sigmoid(x): return 1/(1+np.exp(-x))
class factorizationMachine: #x: a sample in train_set #cross_v: it is a two-dimensional numpy, whose shape is (k,n).And n is sample's feature number. def __init__(self, w0, linear_w, cross_v): self.w0 = w0 self.linear_w = linear_w self.cross_v = cross_v
#def pi_map(self, i): def inference(self, x): return self.w0 + self.linear_w.dot(x) + np.sum((self.cross_v.dot(x))**2) - np.sum((self.cross_v**2).dot(x**2)) def loss(self, y, x): # y_ is predicted value, y is real value y_ = self.inference(x) #L2 regularization loss = -log(sigmoid(y*y_)) + REGULARIZATION_COEFFICIENT * (self.w0**2 + np.sum(self.linear_w**2) + np.sum(self.cross_v**2)) return loss def sgd(self, x, training_steps): self.w0 = self.w0 - pow(LEARNING_RATE, training_steps//STEP_THRESHOLD)*(1 + 2*REGULARIZATION_COEFFICIENT*self.w0) self.linear_w = self.linear_w - pow(LEARNING_RATE, training_steps//STEP_THRESHOLD)*(x + 2*REGULARIZATION_COEFFICIENT*self.linear_w) # v's gradient descent X = np.repeat(x.reshape((1,-1)), self.cross_v.shape[0], axis=0) X_square = X ** 2 mid_mat = self.cross_v.dot(x) aux_matrix = np.repeat(mid_mat.reshape((-1, 1)), x.size, axis=1) self.cross_v =self.cross_v - pow(LEARNING_RATE, training_steps//STEP_THRESHOLD) * (X * aux_matrix - X_square * self.cross_v + 2 * REGULARIZATION_COEFFICIENT * self.cross_v) if __name__ == "__main__": #x = np.random.randn(3) x = np.array([-1.84753684, 1.30561765, 1.95972212]) y = -1 w0 = 0 linear_w = np.zeros(x.size) #cross_v = np.random.normal(loc=0, scale=1, size=(K, x.size)) cross_v = np.array([[-1.41691403, -1.48210948, -0.88291598], [ 1.0972494, 0.99061111, -1.09201868], [-0.3598063, 0.93424249, 1.23286087], [-0.63127532, 1.55323683 , -0.26382005], [ 0.55052691, -1.61802769, -0.50357173], [-0.50000688, 2.36227975, -0.42941842]]) fm = factorizationMachine(w0, linear_w, cross_v) #print(fm.inference(x)) #print("loss is: ", fm.loss(y, x)) print(fm.sgd(x, 10000)) print(fm.cross_v) print(fm.cross_v - cross_v)