• Tensor数据转换为稀疏矩阵


    Tensor数据转换为稀疏矩阵

    一、稀疏矩阵

    原文链接

    常用的稀疏矩阵存储格式有COO,CSR/CSC,LIL

    1.COO

    COO(Coordinate format )是最为简单的格式,以三元组的形式存储稀疏矩阵。记录矩阵中非零元素的数值和所在的行序号和列序号。形式为(行号,列号,数值)。这种存储方式的主要优点是灵活、简单。但是缺点是不可以直接进行矩阵的相关运算

    image-20230909002327571

    2.CSR/CSC

    CSR(Compressed Sparse Row)格式实现了用于存储二维张量的 CSR 格式。尽管不支持 N 维张量,但与 COO 格式相比的主要优势是更好地利用存储和更快的计算操作。目前尚不存在 CUDA 支持

    image-20230909002457546

    3.LIL

    LIL (List-of-List) 每行存储一个列表,每个条目包含列索引和值。通常,这些条目按列索引进行排序,以便更快地查找

    4.稀疏矩阵的处理

    Pytorch中,处理稀疏矩阵的有效工具torch.sparse。Torch 支持 COO(rdinate) 格式的稀疏张量,可以有效地存储和处理大多数元素为零的张量

    二、Tensor数据转换为稀疏矩阵

    1.torch.spares_coo_tenso
    torch.spares_coo_tensor(indices, values, siez=None,*, dtype=None, requires_grad=False)->Tensor
    
    • 1

    参数:

    • indices: 一个2D张量,其中每一列都代表一个非零元素的坐标。
    • values: 一个1D张量,其中每个值都是与indices对应坐标中的非零元素对应的值。
    • size: (可选) 一个表示稀疏张量大小的元组

    假设一个2D的tensor数据

    0 0 0 5
    0 0 3 0
    0 2 0 0
    
    • 1
    • 2
    • 3

    非零元素的坐标(indices)和对应的值(values)为:

    indices = [[0, 3],
               [1, 2],
               [2, 1]]
    
    values = [5, 3, 2]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以使用torch.sparse_coo_tensor来创建这个稀疏张量:

    import torch
    
    indices = torch.tensor([[0, 1, 2],
                            [3, 2, 1]])
    values = torch.tensor([5, 3, 2])
    size = (3, 4)
    
    sparse_tensor = torch.sparse_coo_tensor(indices, values, size)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    2.将一个2D的Tensor数据变为COO稀疏张量
    import torch
    
    # 示例张量
    tensor = torch.tensor([[0, 2, 1], [0, 0, 3], [4, 0, 0]])
    
    # 寻找非零元素的索引
    non_zero_indices = torch.nonzero(tensor).t()
    print(non_zero_indices[0])  # tensor([0, 0, 1, 2])
    print(non_zero_indices[1])  # tensor([1, 2, 2, 0])
    
    print(tensor.dim())  # 2
    
    # 获取非零元素的值
    values = tensor[tuple(non_zero_indices[i] for i in range(tensor.dim()))]
    
    print(values)  # tensor([2, 1, 3, 4])
    
    print(tensor.size())  # torch.Size([3, 3])
    
    # 创建稀疏张量
    sparse_tensor = torch.sparse_coo_tensor(non_zero_indices, values, tensor.size())
    
    print(sparse_tensor)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    最后得到的稀疏矩阵

    tensor(indices=tensor([[0, 0, 1, 2],
                           [1, 2, 2, 0]]),
           values=tensor([2, 1, 3, 4]),
           size=(3, 3), nnz=4, layout=torch.sparse_coo)
    
    • 1
    • 2
    • 3
    • 4
    3.将一个3Dtensor数据转换为COO稀疏张量

    仍然可以使用torch.sparse_coo_tensor函数将其转换为稀疏表示。与2D张量相似,你需要确定非零元素的位置和它们的值。对于3D张量,每个非零元素的坐标将由三个值表示

    import torch
    
    # 示例3D张量
    tensor = torch.tensor([
        [[0, 2, 0], [0, 0, 3], [4, 0, 0]],
        [[0, 0, 0], [0, 5, 0], [0, 0, 6]]
    ])
    
    print(tensor.dim()) # 3
    
    # 寻找非零元素的索引
    non_zero_indices = torch.nonzero(tensor).t()
    print(non_zero_indices[0])  # tensor([0, 0, 0, 1, 1])
    print(non_zero_indices[1])  # tensor([0, 1, 2, 1, 2])
    print(non_zero_indices[2])  # tensor([1, 2, 0, 1, 2])
    
    
    # 获取非零元素的值
    values = tensor[tuple(non_zero_indices[i] for i in range(tensor.dim()))]
    
    # 创建稀疏张量
    sparse_tensor = torch.sparse_coo_tensor(non_zero_indices, values, tensor.size())
    
    print(sparse_tensor)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    4.将一个未知维度的张量数据转换为COO稀疏张量,并且存储到硬盘
    """
    	将tensor 数据转换为COO 稀疏张量函数    
    """
    def tensor_to_sparse(dense_tensor):
        size = dense_tensor.size()
        # 寻找非零元素的索引
        non_zero_indices = torch.nonzero(dense_tensor).t()
        # 获取非零元素的值
        values = dense_tensor[tuple(non_zero_indices[i] for i in range(dense_tensor.dim()))]
        # 创建稀疏张量
        sparse_tensor = torch.sparse_coo_tensor(non_zero_indices, values, size)
    
        return sparse_tensor,size
          
    # 随机产生一个4D张量数据
    dense_tensor = torch.randn((2,3,3,3))
    print(dense_tensor)
    print(dense_tensor.dim())   # 4
    
    sparse_tensor,size = tensor_to_sparse(dense_tensor)
    print(sparse_tensor)
    print(size)    # torch.Size([2, 3, 3, 3])
            
    # 保存稀疏张量到硬盘
    torch.save(sparse_tensor, "spare_tensor.npz")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    5.读取硬盘上存储的COO稀疏张量,并且转换为原来的tensor数据(dense_tensor)
    # 从硬盘上加载稀疏张量
    loaded_sparse_tensor = torch.load("spare_tensor.npz")
        
    """
    	COO 稀疏张量转换为密集张量    
    """
    def sparse_to_tensor(loaded_sparse_tensor):
    	# 将稀疏张量复原为原始的密集张量
    	dense_tensor = loaded_sparse_tensor.to_dense()
            
       	return dense_tensor
     
    # 调用函数
    sparse_to_tensor(loaded_sparse_tensor)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    5.使用scipy包完成上述操作
    import scipy.sparse
    import torch
    import scipy.sparse
    
    
    
    def tensor_to_sparse(dense_tensor):
        # 将dense_tensor转化为2D
        shape = dense_tensor.shape
        tensor_2d = dense_tensor.view(-1, shape[-1])
    
        # 将2D tensor转化为numpy array
        array_2d = tensor_2d.numpy()
    
        # 从numpy array创建sparse matrix
        sparse_matrix = scipy.sparse.coo_matrix(array_2d)
    
        return sparse_matrix,shape
    
    
    def sparse_to_tensor(sparse_matrix, original_shape):
        # 从稀疏矩阵转换为2D array
        array_2d = sparse_matrix.toarray()
    
        # 将2D array转换为original_shape_array
        original_shape_array = array_2d.reshape(original_shape)
    
        # 将3D array转换为3D tensor
        dense_tensor = torch.from_numpy(original_shape_array)
    
        return dense_tensor
    
    # 随机产生一个dense_tensor
    dense_tensor = torch.randn((2,3,3,3))
    
    
    
    # 转化为sparse matrix
    sparse_matrix,original_shape = tensor_to_sparse(dense_tensor)
    print(original_shape)
    
    
    # 将sparse matrix保存到硬盘上
    scipy.sparse.save_npz('sparse_matrix.npz', sparse_matrix)
    
    # 使用scipy.sparse.load_npz从硬盘加载保存的稀疏张量
    loaded_sparse_matrix = scipy.sparse.load_npz('sparse_matrix.npz')
    
    
    # 稀疏张量复原为原来的tensor数据
    restored_tensor = sparse_to_tensor(loaded_sparse_matrix, original_shape)
    
    
    print(restored_tensor)
    
    # 判断restored_tensor与原来的tensor数据是否一致
    print(dense_tensor==restored_tensor)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
  • 相关阅读:
    AutoCAD Civil 3D中文本地化模板下载及设置
    nginx配置指南
    c语言小项目(三子棋游戏实现)
    【运维自动化-配置平台】如何使用云资源同步功能(腾讯云为例)
    第152篇 Solidity 中的 Call
    Redis集群|集群搭建|集群Jedis开发
    平台卡卷API文档分享
    Debian利用现有软件包或者光盘镜像搭建本地软件源
    9、鸿蒙应用桌面图标外观和国际化
    按键中断实验
  • 原文地址:https://blog.csdn.net/A2000613/article/details/132773495