Keras 作为神经网络输出的双曲坐标(Poincaré;嵌入)

Keras 作为神经网络输出的双曲坐标(Poincaré;嵌入),keras,neural-network,Keras,Neural Network,我正在尝试构建一个深度学习预测器,它将一组单词向量(在欧几里得空间中)作为输入,并输出庞加莱嵌入。到目前为止,我运气不太好,因为模型预测的是n维实空间中的任意点,而不是双曲空间。这会导致距离,因此损失函数未定义。因此,我需要以某种方式限制模型的输出。我试过几种方法 首先是定义最小化双曲线距离的损失函数(在庞加莱超光盘上): 我有点哑口无言地把它举起来 然而,它本身似乎不能正常工作。下一步是将优化器更改为我在本主题中提到的内容,然后。请注意,我将Keras 2.1.6与Tensorflow一起使用

我正在尝试构建一个深度学习预测器,它将一组单词向量(在欧几里得空间中)作为输入,并输出庞加莱嵌入。到目前为止,我运气不太好,因为模型预测的是n维实空间中的任意点,而不是双曲空间。这会导致距离,因此损失函数未定义。因此,我需要以某种方式限制模型的输出。我试过几种方法

首先是定义最小化双曲线距离的损失函数(在庞加莱超光盘上):

我有点哑口无言地把它举起来

然而,它本身似乎不能正常工作。下一步是将优化器更改为我在本主题中提到的内容,然后。请注意,我将Keras 2.1.6与Tensorflow一起使用,因此我必须进行一些更改

def get_normalization(p):
    p_norm = K.sum(K.square(p), -1, keepdims=True)
    mp = K.square(1 - p_norm)/4.0
    return mp, K.sqrt(p_norm)


def project(p, p_norm):
    p_norm_clip = K.maximum(p_norm, 1.0)
    p_norm_cond = K.cast(p_norm > 1.0, dtype='float') * K.epsilon()
    return p/p_norm_clip - p_norm_cond

class AdamPoincare(Adam):
    @interfaces.legacy_get_updates_support
    def get_updates(self,loss,params):
        grads = self.get_gradients(loss, params)
        self.updates = [K.update_add(self.iterations, 1)]

        lr = self.lr
        if self.initial_decay > 0:
            lr = lr * (1. / (1. + self.decay * K.cast(self.iterations,
                                                      K.dtype(self.decay))))

        t = K.cast(self.iterations, K.floatx()) + 1
        lr_t = lr * (K.sqrt(1. - K.pow(self.beta_2, t)) /
                     (1. - K.pow(self.beta_1, t)))

        ms = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
        vs = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]

        self.weights = [self.iterations] + ms + vs

        for p, g, m, v in zip(params, grads, ms, vs):

            normalization, p_norm = get_normalization(p)
            g = normalization * g

            m_t = (self.beta_1 * m) + (1. - self.beta_1) * g
            v_t = (self.beta_2 * v) + (1. - self.beta_2) * K.square(g)
            p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)

            self.updates.append(K.update(m, m_t))
            self.updates.append(K.update(v, v_t))

            new_p = project(p_t, p_norm)

            # Apply constraints.
            if getattr(p, 'constraint', None) is not None:
                new_p = p.constraint(new_p)

            self.updates.append(K.update(p, new_p))
        return self.updates
这也没有达到我想要的效果,所以最后我尝试添加一个lambda层,在向前传球时投射点(尽管我不知道这是否合适)。目标输出已经是双曲线空间中的坐标(因此,在向后传递时,这应该是无操作)

但它仍然会产生垃圾结果(不会使距离最小化,或者在后续求值时导致NaN/Inf)。现在,这些实现中的任何一个都可能存在bug,或者整个想法都是无效的。我现在真的不知道。具体目标是一种监督实体链接形式,其中输入是上下文中的目标词,输出是表示结构化本体的庞加莱嵌入点

我确实找到了一个()试图通过重新参数化模型来实现这一点,但我无法从他们的描述中判断如何实现这一点。不过,它确实简洁地描述了这个问题


我很好奇,你是否曾经到这里工作过。我遇到了你在这里描述的类似问题,模型学习和推广得很好(与随机模型相比),但预测本身并不十分有用或准确,即预测庞加莱向量并查找最接近的“真”向量与真类别相差甚远。我很好奇你是否曾经这样做过。我遇到了你们在这里描述的类似问题,模型确实学习和推广得很好(与随机模型相比),但预测本身并不十分有用或准确,也就是说,预测庞加莱向量并查找最接近的“真”向量与真类别相差甚远。
def get_normalization(p):
    p_norm = K.sum(K.square(p), -1, keepdims=True)
    mp = K.square(1 - p_norm)/4.0
    return mp, K.sqrt(p_norm)


def project(p, p_norm):
    p_norm_clip = K.maximum(p_norm, 1.0)
    p_norm_cond = K.cast(p_norm > 1.0, dtype='float') * K.epsilon()
    return p/p_norm_clip - p_norm_cond

class AdamPoincare(Adam):
    @interfaces.legacy_get_updates_support
    def get_updates(self,loss,params):
        grads = self.get_gradients(loss, params)
        self.updates = [K.update_add(self.iterations, 1)]

        lr = self.lr
        if self.initial_decay > 0:
            lr = lr * (1. / (1. + self.decay * K.cast(self.iterations,
                                                      K.dtype(self.decay))))

        t = K.cast(self.iterations, K.floatx()) + 1
        lr_t = lr * (K.sqrt(1. - K.pow(self.beta_2, t)) /
                     (1. - K.pow(self.beta_1, t)))

        ms = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
        vs = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]

        self.weights = [self.iterations] + ms + vs

        for p, g, m, v in zip(params, grads, ms, vs):

            normalization, p_norm = get_normalization(p)
            g = normalization * g

            m_t = (self.beta_1 * m) + (1. - self.beta_1) * g
            v_t = (self.beta_2 * v) + (1. - self.beta_2) * K.square(g)
            p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)

            self.updates.append(K.update(m, m_t))
            self.updates.append(K.update(v, v_t))

            new_p = project(p_t, p_norm)

            # Apply constraints.
            if getattr(p, 'constraint', None) is not None:
                new_p = p.constraint(new_p)

            self.updates.append(K.update(p, new_p))
        return self.updates
def poincare_project(x, axis=-1):
    square_sum = K.tf.reduce_sum(
        K.tf.square(x), axis, keepdims=True)
    x_inv_norm = K.tf.rsqrt(square_sum)
    x_inv_norm = K.tf.minimum((1. - K.epsilon()) * x_inv_norm, 1.)
    outputs = K.tf.multiply(x, x_inv_norm)
    return outputs


x_dense = Dense(int(params["semantic_dense"]))(x_activation)
x_activation = activation(x_dense)
x_output = Dense(params["semantic_dim"], activation="tanh")(x_activation)
x_project = Lambda(poincare_project)(x_output)