11import tensorflow as tf
22from dis_model import DIS
33from gen_model import GEN
4+
45import pickle
56import numpy as np
67import utils as ut
78import multiprocessing
89
10+
911cores = multiprocessing .cpu_count ()
1012
11- #########################################################################################
12- # Hyper-parameters
13- #########################################################################################
1413EMB_DIM = 5
1514USER_NUM = 943
1615ITEM_NUM = 1683
17- BATCH_SIZE = 64
16+ BATCH_SIZE = 16
1817INIT_DELTA = 0.05
1918
2019all_items = set (range (ITEM_NUM ))
2120workdir = 'ml-100k/'
2221DIS_TRAIN_FILE = workdir + 'dis-train.txt'
2322
24- #########################################################################################
25- # Load data
26- #########################################################################################
2723user_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 ])
3834 user_pos_train [uid ] = [iid ]
3935
4036user_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
5754def 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+
6967def 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+
142142def 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
226217if __name__ == '__main__' :
227- main ()
218+ main ()
0 commit comments