首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >keras/tensorflow中的树结构输入

keras/tensorflow中的树结构输入
EN

Stack Overflow用户
提问于 2019-11-15 11:47:20
回答 1查看 485关注 0票数 1

对于一些学校项目,我正在尝试实现一个树卷积,如“树结构上的卷积神经网络用于编程语言处理”Lili Mou,等。

目标

基本上,结果应该是一个神经网络。该网络的样本是二叉树,其节点具有固定长度的特征,如1xN。对我来说,最具挑战性的是树形的自由。这意味着样本树可能具有任意形状的任意数量的节点。一棵左深的树,右深的树,完整的树都是可能的.唯一的限制是它们都应该是二叉树。

用3个加权矩阵W_p, W_l, W_r定义了样本树上的树卷积。这些权重用于树中的每个节点,以生成另一棵具有相同形状但具有不同特性(如1xM )的树(如果权重为NxM形状)。对于每个节点,其特性乘以W_p,其子节点乘以W_l, W_r,因此新树中的节点将包含有关自身及其两个子节点的信息。

最后,在所有的树节点上都有一个动态池层,最后有一个1xM平坦的向量,这样它就可以被输入到一个密集的层中。它的工作方式是,他们将1xM向量的每个条目称为信道。然后,对于每个信道,返回所有节点上的最大值,使其具有1xM向量。

问题

这是对这篇论文的快速解释。现在,正如我在第一段中所说的,问题是这些二叉树的子树的数量是不同的。首先,我尝试使用Keras,但显然它需要层的固定大小的输入。然后发生在我身上,我可以用二叉树的数组实现对每棵树进行固定大小的编码。例如,这意味着节点i的父节点将在2*i2*i+1上拥有其子节点。当某些地方没有子特性时,如果特性的长度为N,则将N零用于填充。

这要求我获得关于所有树的最大索引的信息,这样我就可以创建一些AxN数组,其中A是这个固定大小模式中使用的最大索引。遗憾的是,输入树可能很深,节点较少,所以为了编码16个节点,我必须创建一个60000xN6000xN数组,其中大部分都是零填充的,因为树不是很好的平衡。

然后,我切换到一个自定义SGD实现,在那里我定义了密集,树卷积,动态池快速。向前传球真的很容易。然而,在后台,我可以将导数从稠密传播到池到树,然后在树中进行权重更新,而不是对前面的树进行更新。由于Keras/TF在背景中处理分化,因此实际上更容易。

现在,我真的感到在选择解决这个问题的方法之间陷入了困境。显然,Keras/TF有很多功能可用于设计这样的网络。应该有一种有效的方法将这个树结构的数据传递给这些库,这样,对于30个节点,我就不会以创建60000个节点和59970个向量结束了?为大约15个节点生成6000个或60000个节点的想法在这一点上是疯狂的,即使你得到了最好的GPU。

或者我应该在纸上导出导数方程来继续自定义SGD实现?

作为参考,这是Keras的样子,上面提到的树的编码效率很低。

代码语言:javascript
复制
class MyLayer(Layer):

    def __init__(self, output_dim, **kwargs):
        self.output_dim = output_dim
        super(MyLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        # Create a trainable weight variable for this layer
        self.kernel = self.add_weight(name='kernel',
                                      shape=(3, input_shape[2], self.output_dim[1]),
                                      initializer='ones',
                                      trainable=True)
        super(MyLayer, self).build(input_shape)  # Be sure to call this at the end

    def call(self, x):
        _, tree_size, feature_size = K.int_shape(x)

        new_tree = []
        for i in range(tree_size // 2):
            parent = tf.gather_nd(x, (0,i))
            left = tf.gather_nd(x, (0, 2*i + 1) )
            right = tf.gather_nd(x, (0, 2*i + 2))
            p_l_r = K.expand_dims(K.stack([parent, left, right]), axis = 1)
            product = K.sum(K.batch_dot(p_l_r, self.kernel), axis = 0)
            new_tree.append(product)
        for j in range (tree_size //2, tree_size):
            parent = tf.gather_nd(x, (0, j))
            parent = K.expand_dims(parent, axis = 0)
            product = K.dot(parent, self.kernel[0])
            new_tree.append(product)

        new_tree = K.stack(new_tree, axis = 1)
        return new_tree
    def compute_output_shape(self, input_shape):
        return (input_shape[0], self.output_dim[0], self.output_dim[1])
EN

回答 1

Stack Overflow用户

发布于 2020-08-08 23:06:55

过去,Tensorflow有一个决策树实现。您可以看到它在这里使用的数据结构(变量):https://github.com/tensorflow/tensorflow/blob/v0.10.0rc0/tensorflow/contrib/tensor_forest/python/tensor_forest.py#L155

它显示,您可以通过创建(max_nodes, max_children)形状的2D张量来实现一棵树。(i, j)条目有一个整数,它以相同的张量表示ith节点的jth子节点的索引。因此,具有三个节点的倒V型二叉树将是[[1, 2], [-1, -1], [-1, -1]]

您可以很容易地创建第二个张量来保存这些特性,其中ith行保存ith节点的特性。然后就可以执行您提到的卷积运算,尽管它需要循环。我不认为有一种方法可以将其矢量化,但这是使用(某种程度上)稀疏表示的代价。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58876412

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档