【问题标题】:Best way to convert a tensor from a condensed representation从压缩表示转换张量的最佳方法
【发布时间】:2020-07-19 05:07:43
【问题描述】:

我有一个表示稀疏 3-D 矩阵的压缩格式的张量。我需要将其转换为普通矩阵(它实际代表的矩阵)。 因此,就我而言,矩阵的任何二维切片的每一行都只能包含一个非零元素。那么,作为数据,我拥有这些行中的每一行、值和它出现的索引。例如张量

inp = torch.tensor([[ 1,  2],
 [ 3,  4],
 [-1,  0],
 [45,  1]])

表示一个4x5矩阵(第一维来自张量的第一维,第二维来自元数据)A,其中A[0][2] = 1, A[1][4] = 3, A[2][0] = -1, A[3][1] = 45

这只是我的矩阵的一个二维切片,我有可变数量的这些。 我能够使用 sparse_coo_tensor 以下列方式对上述二维切片执行此操作:

>>> torch.sparse_coo_tensor(torch.stack([torch.arange(0, 4), inp.t()[1]]), inp.t()[0], [4,5]).to_dense()
tensor([[ 0,  0,  1,  0,  0],
        [ 0,  0,  0,  0,  3],
        [-1,  0,  0,  0,  0],
        [ 0, 45,  0,  0,  0]])

这是实现这一目标的最佳方式吗?有没有更简单、更易读的替代方案? 如何在不循环的情况下将其扩展到 3-D 矩阵? 对于 3-D 矩阵,您可以想象输入类似于

inp_list = torch.stack([inp, inp, inp, inp])

所需的输出将是上述输出堆叠 4 次。

如果我正确地创建了一个索引数组,我觉得我应该能够做一些事情,但我想不出不使用某种循环的方法来做到这一点。

【问题讨论】:

    标签: python pytorch tensor advanced-indexing


    【解决方案1】:

    好的,在对不同类型的索引进行了大量实验之后,我得到了这个工作。事实证明,答案在高级索引中。不幸的是,PyTorch 文档没有详细介绍高级索引。 Here is a link for it in the Numpy documentation.

    对于上述问题,这个命令可以解决问题:

    >>> k_lst = torch.zeros([4,4,5])
    >>> k_lst[torch.arange(4).unsqueeze(1), torch.arange(4), inp_list[:,:,1]] = inp_list[:,:,0].float()
    >>> k_lst
    tensor([[[ 0.,  0.,  1.,  0.,  0.],
         [ 0.,  0.,  0.,  0.,  3.],
         [-1.,  0.,  0.,  0.,  0.],
         [ 0., 45.,  0.,  0.,  0.]],
        [[ 0.,  0.,  1.,  0.,  0.],
         [ 0.,  0.,  0.,  0.,  3.],
         [-1.,  0.,  0.,  0.,  0.],
         [ 0., 45.,  0.,  0.,  0.]],
        [[ 0.,  0.,  1.,  0.,  0.],
         [ 0.,  0.,  0.,  0.,  3.],
         [-1.,  0.,  0.,  0.,  0.],
         [ 0., 45.,  0.,  0.,  0.]],
        [[ 0.,  0.,  1.,  0.,  0.],
         [ 0.,  0.,  0.,  0.,  3.],
         [-1.,  0.,  0.,  0.,  0.],
         [ 0., 45.,  0.,  0.,  0.]]])
    

    这正是我想要的。

    我在寻找这个的过程中学到了很多东西,我想把这个分享给任何偶然发现这个问题的人。那么,为什么会这样呢?答案在于Broadcasting 的工作方式。如果您查看所涉及的不同索引张量的形状,您会发现它们(必然)是可广播的。

    >>> torch.arange(4).unsqueeze(1).shape, torch.arange(4).shape, inp_list[:,:,1].shape
    (torch.Size([4, 1]), torch.Size([4]), torch.Size([4, 4]))
    

    显然,要访问 3-D 张量的元素,例如此处的 k_lst,我们需要 3 个索引 - 每个维度一个。如果给[]算子提供3个形状相同的张量,它可以通过匹配这3个张量中的对应元素得到一堆合法的索引。

    如果 3 个张量具有不同的形状,但可广播(如这里的情况),它会将缺少的张量的相关行/列复制必要的次数以获得具有相同形状的张量。

    最终,在我的例子中,如果我们研究不同的值是如何分配的,这将相当于做

    k_lst[0,0,inp_list[0,0,1]] = inp_list[0,0,0].float()
    k_lst[0,1,inp_list[0,1,1]] = inp_list[0,1,0].float()
    k_lst[0,2,inp_list[0,2,1]] = inp_list[0,2,0].float()
    k_lst[0,3,inp_list[0,3,1]] = inp_list[0,3,0].float()
    k_lst[1,0,inp_list[1,0,1]] = inp_list[1,0,0].float()
    k_lst[1,1,inp_list[1,1,1]] = inp_list[1,1,0].float()
    .
    .
    .
    k_lst[3,3,inp_list[3,3,1]] = inp_list[3,3,0].float()
    

    这种格式让我想起了torch.Tensor.scatter(),但是如果能用它来解决这个问题,我还没想好怎么办。

    【讨论】:

      【解决方案2】:

      我相信你的意思是你有一个稀疏张量并且想要转换它。以tf.sparse.to_dense 开头,然后以tensorflow.Tensor.eval() 结尾

      【讨论】:

      • 对不起。它不是一个稀疏张量。数据格式略有不同。稀疏张量将具有索引列表和关联值列表。我所拥有的基本上是一个列表,其中每一行都有一个索引,该行的值。事实上,我有一份这样的清单。另外,为了记录,我正在使用 PyTorch。我认为 Tensorflow 的答案也应该足够了,因为我认为将一个转换为另一个应该不难。谢谢。
      猜你喜欢
      • 2021-10-14
      • 2014-11-09
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多