一种简单优雅的实现方法
余弦相似度计算公式
$ cos(\vec x,\vec y)=\frac{<\vec x,\vec y>}{|\vec x| |\vec y|} $
最直观实现方式
设user_side_representation
与item_side_representation
的shape=[None, 4]
,其中None
表示batch_size
,4表示embedding_size
。
计算user_side_representation
与item_side_representation
两者的cosine similarity
最直观的实现方式为:
1)求user_side_representation
与item_side_representation
的内积inner_product
;
2)分别计算user_side_representation
与item_side_representation
的L2-norm
,norm_user
与norm_item
;
3)计算inner_product / (norm_user*norm_item)
以上思路是完全按照余弦相似度计算公式进行的,利用TensorFlow
实现如下:
1 | user_side_representation_expand = tf.expand_dims(user_side_representation, axis=1) |
但是该实现方式有个致命的问题:在训练过程中output或者loss值会出现为nan的情况。其原因在与tf.sqrt(x)
中x
过小,导致sqrt()
函数输出为nan
。最终会导致模型无法正确训练。
最实用&优雅实现方式
既然tf.sqrt
函数存在输出为nan
的问题,那么我们就要避免使用tf.sqrt
函数。
再来看下余弦相似度计算公式,其实可以进一步变形:
$ cos(\vec x,\vec y)=\frac{<\vec x,\vec y>}{|\vec x| |\vec y|}=<\vec e_x, \vec e_y> $
我们直接计算$\vec x$与$\vec y$两个向量方向上的单位向量的内积就可以了,这样不需要使用tf.sqrt
函数。
利用TensorFlow
实现如下:
1 | user_side_representation_l2norm = tf.nn.l2_normalize(user_side_representation, axis=1) |
总结
利用TensorFlow
计算余弦相似度,计算两向量的单位向量的内积即可。