多值离散特征(muit-onehot)
推荐系统遇上深度学习(四)--多值离散特征的embedding解决方案
在处理DeepFM数据时,由于每一个离散特征只有一个取值,因此我们在处理的过程中,将原始数据处理成了两个文件,一个记录特征的索引,一个记录了特征的值,而每一列,则代表一个离散特征。
但假如,我们某一个离散特征有多个取值呢?举个例子来说,每个人喜欢的NBA球队,有的人可能喜欢火箭和湖人,有的人可能只喜欢勇士,也有的人喜欢骑士、绿军、猛龙等一大堆。对于这种特征,我们本文将其称为多值离散特征。
根据DeepFM的思想,我们需要将每一个field的特征转换为定长的embedding,即使有多个取值,也是要变换成定长的embedding。
那么,一种思路来了,比如一个用户喜欢两个球队,这个field的特征可能是[1,1,0,0,0,0,0.....0],那么我们使用两次embedding lookup,再取个平均不就好了嘛。
嗯,这的确也许可能是一种思路吧,在tensorflow中,其实有一个函数能够实现我们上述的思路,那就是tf.nn.embedding_lookup_sparse。别着急,我们一步一步来实现多值离散特征的embedding处理过程。
import tensorflow as tf
csv = [
"1,harden|james|curry",
"2,wrestbrook|harden|durant",
"3,|paul|towns",
]
TAG_SET = ["harden", "james", "curry", "durant", "paul","towns","wrestbrook"]
def sparse_from_csv(csv):
ids, post_tags_str = tf.decode_csv(csv, [[-1], [""]])
table = tf.contrib.lookup.index_table_from_tensor(
mapping=TAG_SET, default_value=-1) ## 这里构造了个查找表 ##
split_tags = tf.string_split(post_tags_str, "|")
return tf.SparseTensor(
indices=split_tags.indices,
values=table.lookup(split_tags.values), ## 这里给出了不同值通过表查到的index ##
dense_shape=split_tags.dense_shape)
TAG_EMBEDDING_DIM = 3
embedding_params = tf.Variable(tf.truncated_normal([len(TAG_SET), TAG_EMBEDDING_DIM]))#截断的正态分布
tags = sparse_from_csv(csv)
embedded_tags = tf.nn.embedding_lookup_sparse(embedding_params, sp_ids=tags, sp_weights=None)
with tf.Session() as s:
s.run([tf.global_variables_initializer(), tf.tables_initializer()])
print(s.run([embedded_tags]))
print(s.run(embedding_params))
[array([[-0.13585784, -0.4606956 , -0.31155238],
[ 0.02821189, -0.80487055, -0.7014771 ],
[ 0.2527069 , 0.06115395, -0.22305197]], dtype=float32)]
[[-0.43968475 -1.7722744 0.2279189 ]
[ 0.10022298 -0.08266275 -1.2985536 ]
[-0.06811174 0.47285038 0.13597757]
[ 0.9904324 -0.73272985 -0.9167392 ]
[-0.7143307 0.68751687 -0.3415346 ]
[ 1.2197444 -0.565209 -0.10456932]
[-0.46611196 0.09039259 -1.415611 ]]
embedding_lookup
tf.nn.embedding_lookup函数的用法主要是选取一个张量里面索引对应的元素。tf.nn.embedding_lookup(params, ids):params可以是张量也可以是数组等,id就是对应的索引,其他的参数不介绍。
import tensorflow as tf
p = tf.Variable(tf.random_normal([10,1]))#生成10*1的张量
b = tf.nn.embedding_lookup(p, [1, 3])#查找张量中的序号为1和3的
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(p))
print('haha')
print(sess.run(b))
[[-1.2463812]
[-1.870815 ]]
[[-2.490596 ]
[-1.2463812 ]
[-0.97433823]
[-1.870815 ]
[ 1.5988917 ]
[-0.43845415]
[-1.0347619 ]
[-0.98937106]
[ 0.763335 ]
[-1.6154797 ]]
import tensorflow as tf
import numpy as np
a = [[0.1, 0.2, 0.3], [1.1, 1.2, 1.3], [2.1, 2.2, 2.3], [3.1, 3.2, 3.3], [4.1, 4.2, 4.3]]
a = np.asarray(a)
idx1 = tf.Variable([0, 2, 3, 1], tf.int32)
idx2 = tf.Variable([[0, 2, 3, 1], [4, 0, 2, 2]], tf.int32)
out1 = tf.nn.embedding_lookup(a, idx1)
out2 = tf.nn.embedding_lookup(a, idx2)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
print(sess.run(out1))
print(out1)
print('==================')
print(sess.run(out2))
print(out2)
[[0.1 0.2 0.3]
[2.1 2.2 2.3]
[3.1 3.2 3.3]
[1.1 1.2 1.3]]
Tensor("embedding_lookup_4/Identity:0", shape=(4, 3), dtype=float64)
==================
[[[0.1 0.2 0.3]
[2.1 2.2 2.3]
[3.1 3.2 3.3]
[1.1 1.2 1.3]]
[[4.1 4.2 4.3]
[0.1 0.2 0.3]
[2.1 2.2 2.3]
[2.1 2.2 2.3]]]
Tensor("embedding_lookup_5/Identity:0", shape=(2, 4, 3), dtype=float64)