youtube_tzld_match.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # encoding: utf-8
  2. import pandas as pd
  3. import os
  4. import gc
  5. from deepctr.feature_column import SparseFeat, VarLenSparseFeat, get_feature_names
  6. # from preprocess_tzld210315 import gen_data_set, gen_model_input, gen_model_input_user_emb
  7. from preprocess_tzld210322_gen import gen_data_set, gen_model_input, gen_model_input_user_emb
  8. from sklearn.preprocessing import LabelEncoder
  9. from tensorflow.python.keras import backend as K
  10. from tensorflow.python.keras.models import Model
  11. import tensorflow as tf
  12. import numpy as np
  13. from deepmatch.models import *
  14. from deepmatch.utils import sampledsoftmaxloss
  15. count_train = 1
  16. count_test = 1
  17. #batch_size = 1024
  18. batch_size = 6000
  19. def generate_arrays_from_train(train_set, user_profile, SEQ_LEN):
  20. # x_y 是我们的训练集包括标签,每一行的第一个是我们的图片路径,后面的是我们的独热化后的标签
  21. while 1:
  22. for i in range(0, len(train_set), batch_size):
  23. try:
  24. train_batch = train_set[i: i + batch_size]
  25. train_model_input_batch, train_label_batch = gen_model_input(train_batch, user_profile, SEQ_LEN)
  26. if train_model_input_batch is None or train_label_batch is None:
  27. continue
  28. print("train i: " + str(i) + " len train set " + str(len(train_set)))
  29. print(train_model_input_batch)
  30. print(train_label_batch)
  31. yield (train_model_input_batch, train_label_batch)
  32. except Exception as ex:
  33. print("\n\n generate_arrays_from_train exception ", ex)
  34. continue
  35. def generate_arrays_from_train_bak(train_set, user_profile, SEQ_LEN):
  36. global count_train
  37. # batch_size = 8
  38. while True:
  39. try:
  40. train_batch = train_set[(count_train - 1) * batch_size: count_train * batch_size]
  41. train_model_input_batch, train_label_batch = gen_model_input(train_batch, user_profile, SEQ_LEN)
  42. if count_train % 1000 == 0:
  43. print("count:" + str(count_train) + " len train set " + str(len(train_set)))
  44. count_train = count_train + 1
  45. if count_train * batch_size > len(train_set):
  46. count_train = 1
  47. yield (train_model_input_batch, train_label_batch)
  48. except Exception as ex:
  49. print("\n\n generate_arrays_from_file exception ", ex)
  50. count_train = count_train + 1
  51. continue
  52. def generate_arrays_from_test(train_set, user_profile, SEQ_LEN):
  53. # x_y 是我们的训练集包括标签,每一行的第一个是我们的图片路径,后面的是我们的独热化后的标签
  54. # global count
  55. # batch_size = 8
  56. while 1:
  57. for i in range(0, len(train_set), batch_size):
  58. try:
  59. train_batch = train_set[i: i + batch_size]
  60. # train_model_input_batch, train_label_batch = gen_model_input(train_batch, user_profile, SEQ_LEN)
  61. train_model_input_batch, train_label_batch = gen_model_input_user_emb(train_batch, user_profile, SEQ_LEN)
  62. if train_model_input_batch is None or train_label_batch is None:
  63. continue
  64. print("test i: " + str(i) + " len train set " + str(len(train_set)))
  65. yield (train_model_input_batch, train_label_batch)
  66. except Exception as ex:
  67. print("\n\n generate_arrays_from_test exception ", ex)
  68. continue
  69. def generate_arrays_from_test_bak(train_set, user_profile, SEQ_LEN):
  70. global count_test
  71. # batch_size = 8
  72. while True:
  73. try:
  74. train_batch = train_set[(count_test - 1) * batch_size: count_test * batch_size]
  75. train_model_input_batch, train_label_batch = gen_model_input_user_emb(train_batch, user_profile, SEQ_LEN)
  76. if count_test % 1000 == 0:
  77. print("count:" + str(count_test) + " len train set " + str(len(train_set)))
  78. count_test = count_test + 1
  79. if count_test * batch_size > len(train_set):
  80. count_test = 1
  81. yield (train_model_input_batch, train_label_batch)
  82. except Exception as ex:
  83. print("\n\n generate_arrays_from_file exception ", ex)
  84. count_test = count_test + 1
  85. continue
  86. if __name__ == "__main__":
  87. data = pd.read_csvdata = pd.read_csv("/work/xielixun/dwa_sum_graphembedding_user_action_feature_app_20210225.csv")
  88. print(data[0:5])
  89. sparse_features = ["videoid", "mid",
  90. "videoGenre1", "userRatedVideo1", "userGenre1", "userCity",
  91. "authorid", "userRealplayCount", "videoRealPlayCount", "videoDuration"]
  92. SEQ_LEN = 50
  93. #negsample = 3
  94. negsample = 0
  95. # 1.Label Encoding for sparse features,and process sequence features with `gen_date_set` and `gen_model_input`
  96. # features = ['user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip']
  97. features = ["videoid", "mid",
  98. "videoGenre1", "userRatedVideo1", "userGenre1", "userCity",
  99. "authorid", "userRealplayCount", "videoRealPlayCount", "videoDuration"]
  100. feature_max_idx = {}
  101. data["mid"].replace("unknown", "N000111111D", inplace=True)
  102. data = data[data["mid"] != "unknown"].copy()
  103. data = data[data["mid"] != "N000111111D"].copy()
  104. # 和上面函数的功能是一样的,见 deepMatch DSSM
  105. def add_index_column(param_df, column_name):
  106. values = list(param_df[column_name].unique())
  107. value_index_dict = {value: idx for idx, value in enumerate(values)}
  108. if column_name == "mid":
  109. param_df["uidx"] = param_df[column_name].copy()
  110. param_df["mid"] = param_df[column_name].map(value_index_dict)
  111. feature_max_idx["mid"] = param_df["mid"].max() + 1
  112. add_index_column(data, "mid")
  113. feature_max_idx["videoid"] = data["videoid"].max() + 1
  114. # add_index_column(df_data, "mid")
  115. for idx, column_name in enumerate(features):
  116. lbe = LabelEncoder()
  117. if column_name == "videoGenre1" or column_name == "videoGenre2" or \
  118. column_name == "videoGenre3" or column_name == "userGenre1" or column_name == "userGenre2" or column_name == "userGenre3":
  119. data[column_name].fillna("社会", inplace=True)
  120. if column_name == "userCity":
  121. data[column_name].fillna("北京", inplace=True)
  122. if column_name == "mid":
  123. continue
  124. data["uidx"] = data[column_name].copy()
  125. data["mid"] = lbe.fit_transform(data[column_name])
  126. feature_max_idx["mid"] = data["mid"].max() + 1
  127. elif column_name == "videoid": # 负采样生成的videoid,没有离散化
  128. continue
  129. data["vidx"] = data[column_name].copy()
  130. data["videoid"] = lbe.fit_transform(data[column_name])
  131. feature_max_idx["videoid"] = data["videoid"].max() + 1
  132. else:
  133. data[column_name] = lbe.fit_transform(data[column_name]) + 1
  134. feature_max_idx[column_name] = data[column_name].max() + 1
  135. user_profile = data[["uidx", "mid", "userRatedVideo1", "userGenre1", "userCity", "userRealplayCount",
  136. "videoGenre1", "authorid", "videoRealPlayCount", "videoDuration"]].drop_duplicates('mid')
  137. user_mid_uid = data[["uidx", "mid"]].drop_duplicates('mid')
  138. user_mid_uid.rename(columns={'mid': 'userid'}, inplace=True)
  139. item_profile = data[
  140. ["videoid", "videoGenre1", "authorid", "videoRealPlayCount", "videoDuration"]].drop_duplicates(
  141. 'videoid')
  142. print("item size is: ", len(item_profile))
  143. user_profile.set_index("mid", inplace=True)
  144. del data
  145. gc.collect()
  146. test_path = "/work/xielixun/test_user_video_play_test.csv"
  147. train_path = "/work/xielixun/train_user_video_play.csv"
  148. #test_path = "/work/xielixun/test_user_video_play_test_sample_negtive.csv"
  149. #train_path = "/work/xielixun/train_user_video_play_sample_negtive.csv"
  150. train_set, test_set = gen_data_set(train_path, test_path, user_mid_uid)
  151. embedding_dim = 16
  152. user_feature_columns = [SparseFeat('mid', feature_max_idx['mid'], embedding_dim),
  153. SparseFeat("userRatedVideo1", feature_max_idx['userRatedVideo1'], embedding_dim),
  154. SparseFeat("userGenre1", feature_max_idx['userGenre1'], embedding_dim),
  155. SparseFeat("userCity", feature_max_idx['userCity'], embedding_dim),
  156. SparseFeat("userRealplayCount", feature_max_idx['userRealplayCount'], embedding_dim),
  157. VarLenSparseFeat(SparseFeat('hist_video_id', feature_max_idx['videoid'], embedding_dim,
  158. embedding_name="videoid"), SEQ_LEN, 'mean', 'hist_len'),
  159. ]
  160. item_feature_columns = [SparseFeat('videoid', feature_max_idx['videoid'], embedding_dim),
  161. SparseFeat("videoGenre1", feature_max_idx["videoGenre1"], embedding_dim),
  162. SparseFeat("authorid", feature_max_idx["authorid"], embedding_dim),
  163. SparseFeat("videoRealPlayCount", feature_max_idx["videoRealPlayCount"], embedding_dim),
  164. SparseFeat("videoDuration", feature_max_idx["videoDuration"], embedding_dim)]
  165. feature_names = get_feature_names(user_feature_columns + item_feature_columns)
  166. print("\n\nfeature_names is: ")
  167. print(feature_names)
  168. # 因为下面这几行没有加,导致了错误 tensorflow.python.framework.errors_impl.InvalidArgumentError: assertion failed: [predictions must be <= 1] [Condition x <= y did not hold element-wise:] [x (functional_1/sampled_softmax_layer/ExpandDims:0) = ] [[0.944198132][1.15184534][1.00592339]...] [y (Cast_4/x:0) = ] [1]
  169. K.set_learning_phase(True)
  170. import tensorflow as tf
  171. if tf.__version__ >= '2.0.0':
  172. tf.compat.v1.disable_eager_execution()
  173. model = YoutubeDNN(user_feature_columns, item_feature_columns, num_sampled=3, user_dnn_hidden_units=(64, embedding_dim), dnn_use_bn=True, output_activation='sigmoid')
  174. logdir = os.path.join("log_callbacks_youtube") # Tensorboard需要一个文件夹
  175. if not os.path.exists(logdir):
  176. os.mkdir(logdir)
  177. output_model_file = os.path.join(logdir,
  178. 'youtube_model.h5')
  179. callbacks = [
  180. tf.keras.callbacks.TensorBoard(logdir),
  181. tf.keras.callbacks.ModelCheckpoint(output_model_file,
  182. save_best_only=True),
  183. tf.keras.callbacks.EarlyStopping(patience=5, min_delta=1e-5),
  184. ]
  185. METRICS = [
  186. tf.keras.metrics.TruePositives(name='tp'),
  187. tf.keras.metrics.FalsePositives(name='fp'),
  188. tf.keras.metrics.TrueNegatives(name='tn'),
  189. tf.keras.metrics.FalseNegatives(name='fn'),
  190. tf.keras.metrics.BinaryAccuracy(name='accuracy'),
  191. tf.keras.metrics.Precision(name='precision'),
  192. tf.keras.metrics.Recall(name='recall'),
  193. tf.keras.metrics.AUC(name='auc'),
  194. tf.keras.metrics.AUC(name='auc-ROC', curve='ROC'),
  195. tf.keras.metrics.AUC(name='auc-PRC', curve='PR')
  196. ]
  197. model.compile(
  198. loss=sampledsoftmaxloss,
  199. optimizer='adam',
  200. metrics=METRICS
  201. )
  202. model.fit_generator(generate_arrays_from_train(train_set, user_profile, SEQ_LEN),
  203. steps_per_epoch=len(train_set) // batch_size,
  204. epochs=2, max_queue_size=1, workers=1,
  205. callbacks=callbacks, verbose=1, use_multiprocessing=False)
  206. model.save("./tensorflow_youtubeDNN-026-tzld-1.h5")
  207. all_item_model_input = {"videoid": item_profile['videoid'].values,
  208. "videoGenre1": item_profile['videoGenre1'].values,
  209. "authorid": item_profile['authorid'].values,
  210. "videoRealPlayCount": item_profile['videoRealPlayCount'].values,
  211. "videoDuration": item_profile['videoDuration'].values}
  212. user_embedding_model = Model(inputs=model.user_input, outputs=model.user_embedding)
  213. item_embedding_model = Model(inputs=model.item_input, outputs=model.item_embedding)
  214. user_embs = user_embedding_model.predict_generator(generate_arrays_from_test(test_set, user_profile, SEQ_LEN),
  215. steps=len(test_set) // batch_size,
  216. max_queue_size=10, workers=1, callbacks=callbacks,
  217. verbose=1, use_multiprocessing=False)
  218. item_embs = item_embedding_model.predict(all_item_model_input, batch_size=2 ** 12)
  219. # 得到user embedding
  220. user_layer_model = tf.keras.models.Model(
  221. inputs=[model.user_input],
  222. # outputs=model.get_layer("user_embedding").output
  223. outputs=model.user_embedding
  224. )
  225. user_embeddings = []
  226. # 得到video embedding
  227. video_layer_model = tf.keras.models.Model(
  228. inputs=[model.item_input],
  229. # outputs=model.get_layer("item_embedding").output
  230. outputs=model.item_embedding
  231. )
  232. video_embeddings = []
  233. for index, row in item_profile.iterrows():
  234. # video_id = row["vidx"]
  235. video_id = row["videoid"]
  236. video_input = [
  237. np.reshape(row["videoid"], [1, 1]),
  238. np.reshape(row["videoGenre1"], [1, 1]),
  239. # np.reshape(row["videoGenre2"], [1, 1]),
  240. np.reshape(row["authorid"], [1, 1]),
  241. np.reshape(row["videoRealPlayCount"], [1, 1]),
  242. np.reshape(row["videoDuration"], [1, 1])
  243. ]
  244. video_embedding = video_layer_model(video_input)
  245. embedding_str = ",".join([str(x) for x in video_embedding.numpy().flatten()])
  246. video_embeddings.append([video_id, embedding_str])
  247. df_video_embedding = pd.DataFrame(video_embeddings, columns=["video_id", "video_embedding"])
  248. df_video_embedding.head()
  249. output = "./tensorflow_video_embedding-youtubeDNN-tzld-210322.csv"
  250. df_video_embedding.to_csv(output, index=False)