├── README.txt └── deep_mf.py /README.txt: -------------------------------------------------------------------------------- 1 | Deep-MF 2 | ========== 3 | 4 | Deep-MF uses a simple 2-layer neural network to learn latent embeddings for users and items, using implicit feedback data. The network takes a user's full history of implicit signals as input and tries to predict their recent history (~2 weeks) as output. I'll add a fuller description and a comparison with other methods (IMF, Logistic-MF, word2vec) later when I have the time. 5 | -------------------------------------------------------------------------------- /deep_mf.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mp 2 | import numpy as np 3 | import random 4 | from scipy.spatial.distance import cosine 5 | import tensorflow as tf 6 | import time 7 | 8 | 9 | def init_weights(shape): 10 | return tf.Variable(tf.random_normal(shape, stddev=0.01)) 11 | 12 | def model(X, w_h1, w_h2, w_o, p_keep_input, p_keep_hidden): 13 | X = tf.nn.dropout(X, p_keep_input) 14 | 15 | h1 = tf.nn.relu(tf.matmul(X, w_h1)) 16 | h1 = tf.nn.dropout(h1, p_keep_hidden) 17 | 18 | h2 = tf.nn.relu(tf.matmul(h1, w_h2)) 19 | h2 = tf.nn.dropout(h2, p_keep_hidden) 20 | 21 | return tf.matmul(h2, w_o) 22 | 23 | def train_model(input_counts, output_counts, hidden_units=128, batch_size=100): 24 | 25 | num_users, num_items = input_counts.shape 26 | # Balance pos and neg output weight in cross entropy 27 | pos_weight = num_users * num_items / np.count_nonzero(input_counts) 28 | 29 | # Initialize input + output placeholders 30 | X = tf.placeholder(tf.float32, [None, num_items]) 31 | Y = tf.placeholder(tf.float32, [None, num_items]) 32 | 33 | # Initialize weights 34 | w_h1 = init_weights([num_items, hidden_units]) 35 | w_h2 = init_weights([hidden_units, hidden_units]) 36 | # w_o == item vectors 37 | w_o = init_weights([hidden_units, num_items]) 38 | 39 | # Dropout probabilities 40 | p_keep_input = tf.placeholder("float") 41 | p_keep_hidden = tf.placeholder("float") 42 | 43 | py_x = model(X, w_h1, w_h2, w_o, p_keep_input, p_keep_hidden) 44 | 45 | # Define cost and training procedure 46 | cost = tf.reduce_mean(tf.nn.weighted_cross_entropy_with_logits(py_x, Y, pos_weight)) 47 | train_op = tf.train.AdagradOptimizer(0.1).minimize(cost) 48 | predict_op = tf.argmax(py_x, 1) 49 | 50 | with tf.Session() as sess: 51 | # you need to initialize all variables 52 | tf.initialize_all_variables().run() 53 | 54 | for i in range(1000): 55 | avg_loss = 0 56 | for start, end in zip(range(0, num_users, batch_size), range(batch_size - 1, num_users, batch_size)): 57 | _, loss = sess.run([train_op, cost], feed_dict={X: input_counts[start:end], 58 | Y: output_counts[start:end], 59 | p_keep_input: 0.8, 60 | p_keep_hidden: 0.5}) 61 | avg_loss += loss / (num_users / batch_size) 62 | 63 | if i % 10 == 0: 64 | print('%i iterations finished' % i) 65 | print('cross entropy: %f' % avg_loss) 66 | vecs = w_o.eval() 67 | 68 | return vecs.T 69 | 70 | --------------------------------------------------------------------------------