一种简单优雅的实现方法
余弦相似度计算公式
$ 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计算余弦相似度,计算两向量的单位向量的内积即可。