总述:Youtube在2016年发布的一篇DNN+搜索推荐的文章,名为Deep Neural Networks for YouTube Recommendations,对当时甚至现在各大公司的技术都产生了广泛的影响,博主前段时间也对这篇论文做了下翻译,可以参考:Youtube论文翻译,当时只是笼统的把所有内容都说了一下,但是对里面比较重要的几点没有详细阐述,现在再起一篇文章,对里面的以下几点做详细说明
1:video vectors/user vectors应如何理解、应如何写代码得出
2:因为Youtube视频库巨大,那么在训练多分类模型的时候是怎么具体写代码导致可以正常训练的
3:后续有哪些搜索推荐行业的论文是以这篇文章为基础延伸的
一、video vectors/user vectors应如何理解、应如何写代码得出
我们先从论文中的网络图来看
可以看到所有特征concat之后,然后经过几个MLP层(带Relu激活函数),最后一个MLP层出来的向量就是用户向量,这个也不难理解,因为前面是所有的特征先concat在一起,不管做几次mlp变化,一个样本的原始特征总是在最基础的concat上进行的变化,那么代码中应该如何体现呢?
with tf.variable_scope("mlp"):
x_deep = tf.reshape(tf.concat(x_concat, axis=1), shape=[-1, all_weidu])
for i in range(len(layers)):
x_deep = tf.layers.dense(inputs=x_deep, units=layers[i], activation=tf.nn.relu, name='mlp%d' % i)
with tf.variable_scope("softmax"):
x_soft = tf.concat([x_deep],axis=1)
softmax = tf.layers.dense(inputs=x_soft, units=100, activation=tf.nn.softmax, name='softmax')
prediction = tf.reshape(softmax, [-1])
predictions={"prob": prediction , "user_vector":x_soft}
一般这种esmistor方式只有一个predict,但是因为最后一个mlp层的向量是user-vector,所以要把最后一个层加在predictions中,以便训练出来模型之后,可以用下面的方式给预测出来
preds = Estimator.predict(input_fn=lambda: input_fn(valdation, num_epochs=1, batch_size=64), predict_keys="user_vector")
num = 0
with open("./pred.txt", "w") as fo:
for prob in preds:
num += 1
# fo.write("%f\n" % (prob['concat_1']))
print(len(list(prob['concat_1'])))
fo.close()
print(num)
接下来便可以根据验证集中每个样本的userid匹配上对应的用户向量了!
至于item-vector是怎么来的,从图中可以看出来是softmax层的权重,那么就是训练出来模型之后,把模型的softmax的权重层打印出来即可,因为这一层首先shape就是[视频库的总数量, 256],再次是对每个样本组成的 user-vector和所有视频id做转换,所以自然“权重”就是item-vector,那么要怎么写代码得到呢?
print(Estimator.get_variable_names())
print(Estimator.get_variable_value("Softmax-layer/softmax/kernel").shape)
在代码的main函数中,并非input-fn model-fn,pred版本写这样两行就OK了,打印出来shape就明白了
二、因为Youtube视频库巨大,那么在训练多分类模型的时候是怎么具体写代码导致可以正常训练的
这里我选用nce-loss来进行采样,要知道在计算loss的时候,我们可以用采样loss来进行计算,但是有一步是不可以,那就是计算softmax的时候,因为必须出来所有视频的概率才行,但是这一步博主测试过了,带来的损耗时长还算可以接受
###########得到user-vector + softmax,设置predictions
with tf.variable_scope("mlp"):
x_deep = tf.reshape(tf.concat(x_concat, axis=1), shape=[-1, all_weidu])
for i in range(len(layers)):
x_deep = tf.layers.dense(inputs=x_deep, units=layers[i], activation=tf.nn.relu, name='mlp%d' % i)
with tf.variable_scope("softmax"):
x_soft = tf.concat([x_deep],axis=1)
softmax = tf.layers.dense(inputs=x_soft, units=视频库的总数量, activation=tf.nn.softmax, name='softmax')
prediction = tf.reshape(softmax, [-1])
predictions={"prob": prediction , "user_vector":x_soft}
if mode == tf.estimator.ModeKeys.PREDICT: // 这一部分省略,可以参考这个api的官网
############ 接着就是设置计算nce-loss需要的参数了
with tf.variable_scope("weights-biases"):
weights = weight_variable("weights", [视频库的总数量, 256])
biases = weight_variable("biases", [视频库的总数量])
print("weights.get_shape() = ", weights.get_shape())
print("biases.get_shape() = ", biases.get_shape())
labels = tf.one_hot(tf.cast(labels, tf.int64), 视频库的总数量)
print("new1 labels.get_shape() = ", labels.get_shape())
labels = tf.reshape(tf.argmax(labels, 1), [-1, 1])
print("new2 labels.get_shape() = ", labels.get_shape())
#### 在计算nce-loss的时候,要采样多少个类来计算
num_sampled = 10000
### 采样方法
sampled_values = tf.nn.learned_unigram_candidate_sampler
# 这时候的“对input数据做的最后一个reshape操作后的数据”的shape是(batch_size, 256),每一行数据就是一个user的embedding
with tf.name_scope('loss'):
loss = tf.reduce_mean(
tf.nn.nce_loss(
weights=weights,
biases=biases,
labels=labels,
inputs=x_deep,
num_sampled=num_sampled,
num_classes=FLAGS.target_num))
### 同上省略
if mode == tf.estimator.ModeKeys.EVAL:
然后就可以使用各种优化办法,比如adam来进行优化loss
3:后续有哪些搜索推荐行业的论文是以这篇文章为基础延伸的
博主看过的论文不算多,所以暂时只了解din网络虽然是匹配网络,和这个套路有点区别,但是特征输入到网络中的办法确实一样的,所以din算一个;widedeep也算一个。之后要是了解到新的网络,会补充上来