推荐的本质:
推荐的最终目的就是找到相似的人、相似的物品。进而再进行基于user、item的推荐。
未达到这个目的,可以对用户的行为分析(相似行为的人当作相似的人)、基于内容的分析(如用户的各种标签,根据标签匹配度查看相似的人)。但一个推荐系统可能是一个多策略、多场景方法结合体。
协同过滤:
主要是基于用户和物品的交互行为,进行分析。 传统的协同过滤是基于矩阵分解的。当用户和物品的数据级大了以后,这个方法相当耗时。所以采用了deep的方法。
(1)直接dot, 对交互矩阵进行拟合
def build_model(self):
input_job = layers.Input(shape=(1,))
input_geek = layers.Input(shape=(1,))
emb_job = layers.Embedding(len(self.job_id) + 1, 64, trainable=True, embeddings_regularizer="l2")(input_job)
emb_geek = layers.Embedding(len(self.geek_id) + 1, 64, trainable=True, embeddings_regularizer="l2")(input_geek)
emb_job = layers.Dense(64,activation="relu", use_bias=True, kernel_regularizer="l2", bias_regularizer="l1")(emb_job)
emb_geek = layers.Dense(64,activation="relu", use_bias=True, kernel_regularizer="l2", bias_regularizer="l1")(emb_geek)
dot_v = layers.Dot(axes=-1,normalize=True)([emb_geek, emb_job])
dot_v = layers.Lambda(lambda x: K.squeeze(x, axis=1))(dot_v)
model = Model(inputs=[input_job, input_geek], outputs=dot_v)
adam = Adam(lr=0.00005)
model.compile(optimizer=adam, loss="MSE")
model.summary()
return model
(2)合并后,加dense进行拟合。
def build_model(self):
input_job = layers.Input(shape=(1,))
input_geek = layers.Input(shape=(1,))
emb_job = layers.Embedding(len(self.job_id) + 1, 64, trainable=True, embeddings_regularizer="l2")(input_job)
emb_geek = layers.Embedding(len(self.geek_id) + 1, 64, trainable=True, embeddings_regularizer="l2")(input_geek)
emb_job = layers.Dense(64,activation="relu", use_bias=True, kernel_regularizer="l2", bias_regularizer="l1")(emb_job)
emb_geek = layers.Dense(64,activation="relu", use_bias=True, kernel_regularizer="l2", bias_regularizer="l1")(emb_geek)
mearge = layers.Concatenate()([emb_job, emb_geek])
dot_v = layers.Dense(1)(mearge)
dot_v = layers.Lambda(lambda x: K.squeeze(x, axis=1))(dot_v)
model = Model(inputs=[input_job, input_geek], outputs=dot_v)
adam = Adam(lr=0.00005)
model.compile(optimizer=adam, loss="MSE")
model.summary()
return model
(3)集合隐式子反馈的数据,构建pairloss
def build_model(self):
input_job_p = layers.Input(shape=(1,))
input_job_n = layers.Input(shape=(1,))
input_geek = layers.Input(shape=(1,))
emb_job_p = layers.Embedding(len(self.job_id) + 1, 12, trainable=True)(input_job_p)
emb_job_n = layers.Embedding(len(self.job_id) + 1, 12, trainable=True)(input_job_n)
emb_geek = layers.Embedding(len(self.geek_id) + 1, 12, trainable=True)(input_geek)
emb_job_p = layers.Dense(12,activation="relu", use_bias=True)(emb_job_p)
emb_job_n = layers.Dense(12, activation="relu", use_bias=True)(emb_job_n)
emb_geek = layers.Dense(12,activation="relu", use_bias=True)(emb_geek)
out_ = layers.Dot(axes=-1, normalize=True)([emb_geek, emb_job_p])
out_neg = layers.Dot(axes=-1, normalize=True)([emb_geek, emb_job_n])
out_ = layers.Lambda(lambda x: K.squeeze(x, axis=1))(out_)
out_neg = layers.Lambda(lambda x: K.squeeze(x, axis=1))(out_neg)
loss = layers.Lambda(lambda x: K.relu(0.2 + x[0] - x[1]))([out_neg, out_])
model = Model(inputs=[input_job_p, input_job_n, input_geek], outputs=loss)
adam = Adam(lr=0.00005)
model.compile(optimizer=adam, loss=lambda y_true, y_pred: y_pred)
model.summary()
return model
实验的一些结论:
(1)第一种使用了dot, 两种向量需要长度一致,但是拟合比较简单。
(2)第二种形式上可以允许两端向量不同长,通过MLP增加拟合度。
(3)从实验效果上,(3>(2)>(1), 但是差距上没有很大(2个点内)。