如何使用 tfa.layers.PoincareNormalize 实现 Poincaré 嵌入?

How do I implement Poincaré Embeddings using tfa.layers.PoincareNormalize?

我正在尝试实现 Facebook 论文中讨论的 Poincaré 嵌入 (Link) for my hierarchical data. You may find a more accessible explanation of Poincaré embeddings here

根据这篇论文,我在 Tensorflow Addons 中找到了 Tensorflow here and here as well as tfa.layers.PoincareNormalize 的一些实现。后者甚至对上述论文进行了 link,这让我相信这对我来说可能是一个很好的起点。但是,到目前为止,我没有成功实施 tfa.layers.PoincareNormalize,除了我 link 编辑的 API 页面上的一些通用信息外,我也找不到任何文档。

有谁知道应该如何实现该层以提供论文中讨论的双曲线 space 中的嵌入?我的出发点是使用标准嵌入层的实现,如下所示(它实际上是分类变量的实体嵌入)?

input = Input(shape=(1, ))
model = Embedding(input_dim=my_input_dim, 
                    output_dim=embed_dim, name="my_feature")(input)
model = Reshape(target_shape=(embed_dim, ))(model)
model = Dense(1)(model)
model = Activation('sigmoid')(model)

简单地用 tfa.layers.PoincareNormalize 替换嵌入层是行不通的,因为输入不同。我假设它可以放在嵌入层之后的某个地方,这样对于反向传播步骤,“值”在每次迭代中都被投影成双曲线 space,但到目前为止也没有运气。

庞加莱嵌入

However, while complex symbolic datasets often exhibit a latent hierarchical structure, state-of-the-art methods typically learn embeddings in Euclidean vector spaces, which do not account for this property. For this purpose, we introduce a new approach for learning hierarchical representations of symbolic data by embedding them into hyperbolic space – or more precisely into an n-dimensional Poincaré ball.

Poincaré 嵌入允许您在非欧几里德中创建分层嵌入 space。 Poincaré 球外侧的向量与中心的向量相比层次较低。

将欧几里德度量张量映射到黎曼度量张量的变换是一个开放的 d 维单位球。

此非欧几里德 space 中 2 个向量之间的距离计算为

research paper for Poincaré embeddings 写得非常棒,您也会在流行的库中找到一些非常棒的实现。不用说,他们被低估了。

在 -

中找到了您可以使用的两个实现
  • tensorflow_addons.PoincareNormalize
  • gensim.models.poincare

Tensorflow Addons 实施

根据文档,对于一维张量,tfa.layers.PoincareNormalize 计算沿 axis=0 的以下输出。

          (x * (1 - epsilon)) / ||x||     if ||x|| > 1 - epsilon
output =
           x                              otherwise

对于更高维度的张量,它会沿 维度轴.

独立地归一化每个一维切片

这个转换可以简单地应用于 n-dims 的嵌入。让我们为时间序列的每个元素创建一个 5 dim 嵌入。本例中维度轴=-1,从欧氏space映射到非欧氏space.

from tensorflow.keras import layers, Model, utils
import tensorflow_addons as tfa

X = np.random.random((100,10))
y = np.random.random((100,))


inp = layers.Input((10,))
x = layers.Embedding(500, 5)(inp)
x = tfa.layers.PoincareNormalize(axis=-1)(x)  #<-------
x = layers.Flatten()(x)
out = layers.Dense(1)(x)

model = Model(inp, out)
model.compile(optimizer='adam', loss='binary_crossentropy')
utils.plot_model(model, show_shapes=True, show_layer_names=False)

model.fit(X, y, epochs=3)
Epoch 1/3
4/4 [==============================] - 0s 2ms/step - loss: 7.9455
Epoch 2/3
4/4 [==============================] - 0s 2ms/step - loss: 7.5753
Epoch 3/3
4/4 [==============================] - 0s 2ms/step - loss: 7.2429
<tensorflow.python.keras.callbacks.History at 0x7fbb14595310>

Gensim 实施

另一个实现 Poincare 嵌入可以在 Gensim 中找到。它与您在使用 Gensim 的 Word2Vec 时使用的非常相似。

该过程将是 -

  1. 训练 Gensim 嵌入(word2vec 或 poincare)
  2. 使用嵌入在 Keras 中初始化嵌入层
  3. 将嵌入层设置为不可训练
  4. 为下游任务训练模型
from gensim.models.poincare import PoincareModel

relations = [('kangaroo', 'marsupial'), ('kangaroo', 'mammal'), ('gib', 'cat'), ('cow', 'mammal'), ('cat','pet')]

model = PoincareModel(relations, size = 2, negative = 2)  #Change size for higher dims
model.train(epochs=10)

print('kangroo vs marsupial:',model.kv.similarity('kangaroo','marsupial'))
print('gib vs mammal:', model.kv.similarity('gib','mammal'))

print('Embedding for Cat: ', model.kv['cat'])
kangroo vs marsupial: 0.9481239343527523
gib vs mammal: 0.5325816385250299

Embedding for Cat:  [0.22193988 0.0776986 ]

可以找到有关训练和保存 Poincare 嵌入的更多详细信息 here