Skip to content

Commit b1fc899

Browse files
author
shixiaowen03
committed
IRGAN
1 parent 4a41eef commit b1fc899

7 files changed

Lines changed: 44548 additions & 44495 deletions

File tree

.idea/workspace.xml

Lines changed: 220 additions & 115 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 100 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,27 @@
11
import tensorflow as tf
22
from dis_model import DIS
33
from gen_model import GEN
4+
45
import pickle
56
import numpy as np
67
import utils as ut
78
import multiprocessing
89

10+
911
cores = multiprocessing.cpu_count()
1012

11-
#########################################################################################
12-
# Hyper-parameters
13-
#########################################################################################
1413
EMB_DIM = 5
1514
USER_NUM = 943
1615
ITEM_NUM = 1683
17-
BATCH_SIZE = 64
16+
BATCH_SIZE = 16
1817
INIT_DELTA = 0.05
1918

2019
all_items = set(range(ITEM_NUM))
2120
workdir = 'ml-100k/'
2221
DIS_TRAIN_FILE = workdir + 'dis-train.txt'
2322

24-
#########################################################################################
25-
# Load data
26-
#########################################################################################
2723
user_pos_train = {}
28-
with open(workdir + 'movielens-100k-train.txt')as fin:
24+
with open(workdir + 'movielens-100k-train.txt') as fin:
2925
for line in fin:
3026
line = line.split()
3127
uid = int(line[0])
@@ -38,20 +34,21 @@
3834
user_pos_train[uid] = [iid]
3935

4036
user_pos_test = {}
41-
with open(workdir + 'movielens-100k-test.txt')as fin:
37+
with open(workdir + 'movielens-100k-test.txt') as fin:
4238
for line in fin:
4339
line = line.split()
4440
uid = int(line[0])
4541
iid = int(line[1])
4642
r = float(line[2])
47-
if r > 3.99:
43+
if r>3.99:
4844
if uid in user_pos_test:
4945
user_pos_test[uid].append(iid)
5046
else:
5147
user_pos_test[uid] = [iid]
5248

53-
all_users = sorted(user_pos_train.keys())
5449

50+
all_users = list(user_pos_train.keys())
51+
all_users.sort()
5552

5653

5754
def dcg_at_k(r, k):
@@ -66,16 +63,15 @@ def ndcg_at_k(r, k):
6663
return dcg_at_k(r, k) / dcg_max
6764

6865

66+
6967
def simple_test_one_user(x):
7068
rating = x[0]
7169
u = x[1]
72-
7370
test_items = list(all_items - set(user_pos_train[u]))
74-
item_score = []
71+
item_score=[]
7572
for i in test_items:
76-
item_score.append((i, rating[i]))
77-
78-
item_score = sorted(item_score, key=lambda x: x[1])
73+
item_score.append((i,rating[i]))
74+
item_score = sorted(item_score,key=lambda x:x[1])
7975
item_score.reverse()
8076
item_sort = [x[0] for x in item_score]
8177

@@ -85,18 +81,17 @@ def simple_test_one_user(x):
8581
r.append(1)
8682
else:
8783
r.append(0)
88-
8984
p_3 = np.mean(r[:3])
9085
p_5 = np.mean(r[:5])
9186
p_10 = np.mean(r[:10])
92-
ndcg_3 = ndcg_at_k(r, 3)
93-
ndcg_5 = ndcg_at_k(r, 5)
94-
ndcg_10 = ndcg_at_k(r, 10)
87+
ndcg_3 = ndcg_at_k(r,3)
88+
ndcg_5 = ndcg_at_k(r,5)
89+
ndcg_10 = ndcg_at_k(r,10)
9590

9691
return np.array([p_3, p_5, p_10, ndcg_3, ndcg_5, ndcg_10])
9792

9893

99-
def simple_test(sess, model):
94+
def simple_test(sess,model):
10095
result = np.array([0.] * 6)
10196
pool = multiprocessing.Pool(cores)
10297
batch_size = 128
@@ -109,119 +104,115 @@ def simple_test(sess, model):
109104
user_batch = test_users[index:index + batch_size]
110105
index += batch_size
111106

112-
user_batch_rating = sess.run(model.all_rating, {model.u: user_batch})
113-
user_batch_rating_uid = zip(user_batch_rating, user_batch)
114-
batch_result = pool.map(simple_test_one_user, user_batch_rating_uid)
107+
user_batch_rating = sess.run(model.all_rating,{model.u:user_batch})
108+
user_batch_rating_uid = zip(user_batch_rating,user_batch)
109+
batch_result = pool.map(simple_test_one_user,user_batch_rating_uid)
110+
115111
for re in batch_result:
116112
result += re
117113

114+
118115
pool.close()
119116
ret = result / test_user_num
120117
ret = list(ret)
121118
return ret
122119

123120

124-
def generate_for_d(sess, model, filename):
121+
def generate_for_d(sess,model,filename):
125122
data = []
126123
for u in user_pos_train:
127124
pos = user_pos_train[u]
128125

129-
rating = sess.run(model.all_rating, {model.u: [u]})
130-
rating = np.array(rating[0]) / 0.2 # Temperature
126+
rating = sess.run(model.all_rating,{model.u:[u]})
127+
rating = np.array(rating[0]) / 0.2
131128
exp_rating = np.exp(rating)
132129
prob = exp_rating / np.sum(exp_rating)
133130

134-
neg = np.random.choice(np.arange(ITEM_NUM), size=len(pos), p=prob)
131+
neg = np.random.choice(np.arange(ITEM_NUM),size=len(pos),p=prob)
132+
# 1:1 的正负样本
135133
for i in range(len(pos)):
136134
data.append(str(u) + '\t' + str(pos[i]) + '\t' + str(neg[i]))
137135

138-
with open(filename, 'w')as fout:
136+
with open(filename,'w') as fout:
139137
fout.write('\n'.join(data))
140138

141139

140+
141+
142142
def main():
143-
print ("load model...")
144-
#param = cPickle.load(open(workdir + "model_dns_ori.pkl"))
145-
generator = GEN(ITEM_NUM, USER_NUM, EMB_DIM, lamda=0.0 / BATCH_SIZE, param=None, initdelta=INIT_DELTA,
146-
learning_rate=0.1)
147-
discriminator = DIS(ITEM_NUM, USER_NUM, EMB_DIM, lamda=0.1 / BATCH_SIZE, param=None, initdelta=INIT_DELTA,
148-
learning_rate=0.1)
143+
print("loading model...")
144+
generator = GEN(ITEM_NUM,USER_NUM,EMB_DIM,lamda = 0.0 / BATCH_SIZE,param = None,initdelta= INIT_DELTA,
145+
learning_rate = 0.001)
146+
discriminator = DIS(ITEM_NUM,USER_NUM,EMB_DIM,lamda = 0.1/BATCH_SIZE,param=None,initdelta = INIT_DELTA,
147+
learning_rate = 0.001)
149148

150149
config = tf.ConfigProto()
151-
config.gpu_options.allow_growth = True
152-
sess = tf.Session(config=config)
153-
sess.run(tf.global_variables_initializer())
154-
155-
# print("gen ", simple_test(sess, generator))
156-
# print("dis ", simple_test(sess, discriminator))
157-
158-
dis_log = open(workdir + 'dis_log.txt', 'w')
159-
gen_log = open(workdir + 'gen_log.txt', 'w')
160-
161-
# minimax training
162-
best = 0.
163-
for epoch in range(150):
164-
if epoch >= 0:
165-
for d_epoch in range(5):
166-
if d_epoch % 5 == 0:
167-
generate_for_d(sess, generator, DIS_TRAIN_FILE)
168-
train_size = ut.file_len(DIS_TRAIN_FILE)
169-
index = 1
170-
while True:
171-
if index > train_size:
172-
break
173-
if index + BATCH_SIZE <= train_size + 1:
174-
input_user, input_item, input_label = ut.get_batch_data(DIS_TRAIN_FILE, index, BATCH_SIZE)
175-
else:
176-
input_user, input_item, input_label = ut.get_batch_data(DIS_TRAIN_FILE, index,
177-
train_size - index + 1)
178-
index += BATCH_SIZE
179-
180-
_ = sess.run(discriminator.d_updates,
181-
feed_dict={discriminator.u: input_user, discriminator.i: input_item,
182-
discriminator.label: input_label})
183-
184-
# Train G
185-
for g_epoch in range(5): # 50
186-
for u in user_pos_train:
187-
sample_lambda = 0.2
188-
pos = user_pos_train[u]
189-
190-
rating = sess.run(generator.all_logits, {generator.u: u})
191-
exp_rating = np.exp(rating)
192-
prob = exp_rating / np.sum(exp_rating) # prob is generator distribution p_\theta
193-
194-
pn = (1 - sample_lambda) * prob
195-
pn[pos] += sample_lambda * 1.0 / len(pos)
196-
# Now, pn is the Pn in importance sampling, prob is generator distribution p_\theta
197-
198-
sample = np.random.choice(np.arange(ITEM_NUM), 2 * len(pos), p=pn)
199-
###########################################################################
200-
# Get reward and adapt it with importance sampling
201-
###########################################################################
202-
reward = sess.run(discriminator.reward, {discriminator.u: u, discriminator.i: sample})
203-
reward = reward * prob[sample] / pn[sample]
204-
###########################################################################
205-
# Update G
206-
###########################################################################
207-
_ = sess.run(generator.gan_updates,
208-
{generator.u: u, generator.i: sample, generator.reward: reward})
209-
210-
result = simple_test(sess, generator)
211-
print ("epoch ", epoch, "gen: ", result)
212-
buf = '\t'.join([str(x) for x in result])
213-
gen_log.write(str(epoch) + '\t' + buf + '\n')
214-
gen_log.flush()
215-
216-
p_5 = result[1]
217-
if p_5 > best:
218-
print('best: ', result)
219-
best = p_5
220-
221-
222-
gen_log.close()
223-
dis_log.close()
150+
config.gpu_options.allow_growth=True
151+
with tf.Session(config=config) as sess:
152+
sess.run(tf.global_variables_initializer())
153+
print("gen ",simple_test(sess,generator))
154+
print("dis ",simple_test(sess,discriminator))
155+
156+
dis_log = open(workdir + 'dis_log.txt','w')
157+
gen_log = open(workdir + 'gen_log.txt','w')
158+
159+
best = 0.
160+
for epoch in range(15):
161+
if epoch >= 0:
162+
for d_epoch in range(100):
163+
if d_epoch % 5 == 0:
164+
generate_for_d(sess,generator,DIS_TRAIN_FILE)
165+
train_size = ut.file_len(DIS_TRAIN_FILE)
166+
index = 1
167+
while True:
168+
if index > train_size:
169+
break
170+
if index + BATCH_SIZE <= train_size + 1:
171+
input_user,input_item,input_label = ut.get_batch_data(DIS_TRAIN_FILE,index,BATCH_SIZE)
172+
else:
173+
input_user,input_item,input_label = ut.get_batch_data(DIS_TRAIN_FILE,index,train_size-index+1)
174+
index += BATCH_SIZE
175+
176+
_ = sess.run(discriminator.d_updates,feed_dict={
177+
discriminator.u:input_user,discriminator.i:input_item,discriminator.label:input_label
178+
})
179+
180+
for g_epoch in range(50):
181+
for u in user_pos_train:
182+
sample_lambda = 0.2
183+
pos = user_pos_train[u]
184+
185+
rating = sess.run(generator.all_logits,{generator.u:u})
186+
exp_rating = np.exp(rating)
187+
prob = exp_rating / np.sum(exp_rating)
188+
189+
pn = (1-sample_lambda) * prob
190+
pn[pos] += sample_lambda * 1.0 / len(pos)
191+
192+
sample = np.random.choice(np.arange(ITEM_NUM), 2 * len(pos), p=pn)
193+
194+
reward = sess.run(discriminator.reward, {discriminator.u: u, discriminator.i: sample})
195+
reward = reward * prob[sample] / pn[sample]
196+
197+
_ = sess.run(generator.gan_updates,
198+
{generator.u: u, generator.i: sample, generator.reward: reward})
199+
200+
result = simple_test(sess, generator)
201+
print("epoch ", epoch, "gen: ", result)
202+
buf = '\t'.join([str(x) for x in result])
203+
gen_log.write(str(epoch) + '\t' + buf + '\n')
204+
gen_log.flush()
205+
206+
p_5 = result[1]
207+
if p_5 > best:
208+
print('best: ', result)
209+
best = p_5
210+
211+
212+
gen_log.close()
213+
dis_log.close()
214+
224215

225216

226217
if __name__ == '__main__':
227-
main()
218+
main()

recommendation/Basic-IRGAN-Demo/dis_model.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,57 @@
11
import tensorflow as tf
22
import pickle
33

4-
54
class DIS():
6-
def __init__(self, itemNum, userNum, emb_dim, lamda, param=None, initdelta=0.05, learning_rate=0.05):
5+
def __init__(self,itemNum,userNum,emb_dim,lamda,param=None,initdelta=0.05,learning_rate =0.05):
76
self.itemNum = itemNum
87
self.userNum = userNum
98
self.emb_dim = emb_dim
10-
self.lamda = lamda # regularization parameters
9+
self.lamda = lamda
1110
self.param = param
1211
self.initdelta = initdelta
1312
self.learning_rate = learning_rate
1413
self.d_params = []
1514

16-
with tf.variable_scope('discriminator'):
15+
with tf.variable_scope("discriminator"):
1716
if self.param == None:
18-
self.user_embeddings = tf.Variable(
19-
tf.random_uniform([self.userNum, self.emb_dim], minval=-self.initdelta, maxval=self.initdelta,
20-
dtype=tf.float32))
21-
self.item_embeddings = tf.Variable(
22-
tf.random_uniform([self.itemNum, self.emb_dim], minval=-self.initdelta, maxval=self.initdelta,
23-
dtype=tf.float32))
24-
self.item_bias = tf.Variable(tf.zeros([self.itemNum]))
17+
self.user_embeddings = tf.Variable(tf.random_uniform([self.userNum,self.emb_dim],
18+
minval=-self.initdelta,maxval=self.initdelta,
19+
dtype=tf.float32))
20+
self.item_embeddings = tf.Variable(tf.random_uniform([self.itemNum,self.emb_dim],
21+
minval=-self.initdelta,maxval=self.initdelta,
22+
dtype=tf.float32))
23+
self.item_bias = tf.Variable(tf.zeros(self.itemNum))
24+
2525
else:
2626
self.user_embeddings = tf.Variable(self.param[0])
2727
self.item_embeddings = tf.Variable(self.param[1])
2828
self.item_bias = tf.Variable(self.param[2])
2929

30-
self.d_params = [self.user_embeddings, self.item_embeddings, self.item_bias]
30+
self.d_params = [self.user_embeddings,self.item_embeddings,self.item_bias]
3131

32-
# placeholder definition
3332
self.u = tf.placeholder(tf.int32)
3433
self.i = tf.placeholder(tf.int32)
3534
self.label = tf.placeholder(tf.float32)
3635

37-
self.u_embedding = tf.nn.embedding_lookup(self.user_embeddings, self.u)
38-
self.i_embedding = tf.nn.embedding_lookup(self.item_embeddings, self.i)
39-
self.i_bias = tf.gather(self.item_bias, self.i)
36+
self.u_embedding = tf.nn.embedding_lookup(self.user_embeddings,self.u)
37+
self.i_embedding = tf.nn.embedding_lookup(self.item_embeddings,self.i)
38+
self.i_bias = tf.gather(self.item_bias,self.i)
4039

4140
self.pre_logits = tf.reduce_sum(tf.multiply(self.u_embedding, self.i_embedding), 1) + self.i_bias
42-
self.pre_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=self.label,
43-
logits=self.pre_logits) + self.lamda * (
41+
self.pre_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = self.label,
42+
logits = self.pre_logits) + self.lamda * (
4443
tf.nn.l2_loss(self.u_embedding) + tf.nn.l2_loss(self.i_embedding) + tf.nn.l2_loss(self.i_bias)
4544
)
4645

4746
d_opt = tf.train.GradientDescentOptimizer(self.learning_rate)
48-
self.d_updates = d_opt.minimize(self.pre_loss, var_list=self.d_params)
47+
self.d_updates = d_opt.minimize(self.pre_loss,var_list=self.d_params)
4948

50-
self.reward_logits = tf.reduce_sum(tf.multiply(self.u_embedding, self.i_embedding),
51-
1) + self.i_bias
49+
self.reward_logits = tf.reduce_sum(tf.multiply(self.u_embedding,self.i_embedding),1) + self.i_bias
5250
self.reward = 2 * (tf.sigmoid(self.reward_logits) - 0.5)
5351

54-
# for test stage, self.u: [batch_size]
55-
self.all_rating = tf.matmul(self.u_embedding, self.item_embeddings, transpose_a=False,
56-
transpose_b=True) + self.item_bias
52+
self.all_rating = tf.matmul(self.u_embedding,self.item_embeddings,transpose_a=False,transpose_b=True) + self.item_bias
5753

58-
self.all_logits = tf.reduce_sum(tf.multiply(self.u_embedding, self.item_embeddings), 1) + self.item_bias
54+
self.all_logits = tf.reduce_sum(tf.multiply(self.u_embedding,self.item_embeddings),1) + self.item_bias
5955
self.NLL = -tf.reduce_mean(tf.log(
6056
tf.gather(tf.reshape(tf.nn.softmax(tf.reshape(self.all_logits, [1, -1])), [-1]), self.i))
6157
)

0 commit comments

Comments
 (0)