pytorch笔记:torch.sparse类

PyTorch 提供了 torch.Tensor 来表示一个包含单一数据类型元素的多维数组。 默认情况下,数组元素连续存储在内存中,从而可以有效地实现各种数组处理算法,这些算法依赖于对数组元素的快速访问。

 然而,存在一类重要的多维数组,即所谓的稀疏数组,其中数组元素的连续内存存储被证明是次优的。 稀疏数组具有大部分元素为零的特性,这意味着如果仅存储或/和处理非零元素,则可以节省大量内存和处理器资源。 

1 构造稀疏矩阵

import torch
i = torch.LongTensor([[0, 1, 1],[2, 0, 2]])   #row, col
v = torch.FloatTensor([3, 4, 5])    #data
torch.sparse.FloatTensor(i, v, torch.Size([2,3])).to_dense()   #torch.Size
'''
tensor([[0., 0., 3.],
        [4., 0., 5.]])
'''

构造方法和 scipy笔记:scipy.sparse_UQI-LIUWJ的博客-CSDN博客 2.2 coo矩阵 的类似

  • 在 PyTorch 中,稀疏张量的填充值不能明确指定,一般假定为零
  • 但是,存在可能以不同方式解释填充值的操作。 例如,torch.sparse.softmax() 计算 softmax 时假设填充值为负无穷大。

1.1 稀疏COO tensor

  •  在 COO 格式(coordinate)中,指定的元素存储为元素索引和相应值的元组。 
    • 元素索引的类型是torch.int64,size是(ndim,nse)
    • 数值类型是任何类型,size是(nse,)
import torch

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [3, 4, 5]

s = torch.sparse_coo_tensor(i, v, (2, 3))
s

'''
tensor(indices=tensor([[0, 1, 1],
                       [2, 0, 2]]),
       values=tensor([3, 4, 5]),
       size=(2, 3), nnz=3, layout=torch.sparse_coo)
'''

s.is_sparse
#True

s.layout
#torch.sparse_coo

 x坐标为0,y坐标为2的元素是3;x坐标为1,y坐标为1的元素是4.。。。 

1.1.0 稀疏矩阵转换成正常Tensor

s.to_dense()
'''
tensor([[0, 0, 3],
        [4, 0, 5]])
'''

1.1.1 COO tensor和正常tensor(strided tensor)空间复杂度对比

  • COO tensor:ndim*8*nse+<element_size>*nse
  • 正常tensor: <tensor_size>*<element_size>

  • 举例 一个10,000*10,000的 float32 Tensor,其中有100,000个非零元素
    • 正常Tensor的话,需要10 000 * 10 000 * 4 = 400 000 000 比特
    • 使用COO tensor的话,需要(2 * 8 + 4) * 100 000 = 2 000 000比特

1.2.3 创建空的COO tensor

torch.sparse_coo_tensor(size=(2, 3))
'''
tensor(indices=tensor([], size=(2, 0)),
       values=tensor([], size=(0,)),
       size=(2, 3), nnz=0, layout=torch.sparse_coo)
'''

1.2.4 混合稀疏COO Tensor

  • 我们可以将前面value值为标量的稀疏张量扩展到value值为连续张量的稀疏张量。
  • 这种张量称为混合张量。
    • 元素索引的类型是torch.int64,size是(ndim,nse)
    • 数值类型是任何类型,size是(nse,dense_dims)
  • 对应的稀疏矩阵的维度是n_dim+dense_dims
import torch

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [[3,2],[4,1],[5,3]]

s = torch.sparse_coo_tensor(i, v, (2, 3,2))
s,s.to_dense()

'''
(tensor(indices=tensor([[0, 1, 1],
                        [2, 0, 2]]),
        values=tensor([[3, 2],
                       [4, 1],
                       [5, 3]]),
        size=(2, 3, 2), nnz=3, layout=torch.sparse_coo),
 tensor([[[0, 0],
          [0, 0],
          [3, 2]],
 
         [[4, 1],
          [0, 0],
          [5, 3]]]))
'''

1.2.5 未合并的稀疏COO 张量

  • PyTorch 稀疏 COO 张量格式允许未合并的稀疏张量,其中索引中可能存在重复坐标;
  • 在这种情况下,该索引处的值是所有重复值条目的总和。
  • 例如,可以为同一个索引 1 指定多个值 3 和 4,这会导致未合并张量:
i = [[1, 1]]
v =  [3, 4]
s=torch.sparse_coo_tensor(i, v, (3,))
s
'''
tensor(indices=tensor([[1, 1]]),
       values=tensor([3, 4]),
       size=(3,), nnz=2, layout=torch.sparse_coo)
'''
s.is_coalesced()
#False

合并(结果仍为稀疏张量) 

s.coalesce()
'''
tensor(indices=tensor([[1]]),
       values=tensor([7]),
       size=(3,), nnz=1, layout=torch.sparse_coo)
'''
s.coalesce().is_coalesced()
# True
s.to_dense()
#tensor([0, 7, 0])

1.2.6 是否需要合并? 

  •  在大多数情况下,不用关心稀疏张量是否被合并,因为在给定合并或未合并稀疏张量的情况下,大多数操作的工作方式相同。
  • 但是,一些操作可以在未合并的张量上更有效地实现,而一些操作可以在合并的张量上更有效地实现。
  • 例如,通过简单地连接索引和值张量来实现稀疏 COO 张量的添加:
a = torch.sparse_coo_tensor([[1, 1]], [5, 6], (2,))
b = torch.sparse_coo_tensor([[0, 0]], [7, 8], (2,))
a + b
'''
tensor(indices=tensor([[0, 0, 1, 1]]),
       values=tensor([7, 8, 5, 6]),
       size=(2,), nnz=4, layout=torch.sparse_coo)
'''

1.2.7 查看indice和value

1)不用事先合并

import torch

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [3, 4, 5]

s = torch.sparse_coo_tensor(i, v, (2, 3))
print(s)
print(s._indices())
print(s._values())

'''
tensor(indices=tensor([[0, 1, 1],
                       [2, 0, 2]]),
       values=tensor([3, 4, 5]),
       size=(2, 3), nnz=3, layout=torch.sparse_coo)
tensor([[0, 1, 1],
        [2, 0, 2]])
tensor([3, 4, 5])
'''

 2) 需要事先合并

print(s.indices())
print(s.values())

'''
RuntimeError                              Traceback (most recent call last)
<ipython-input-27-b4753553cd54> in <module>
      8 s = torch.sparse_coo_tensor(i, v, (2, 3))
      9 print(s)
---> 10 print(s.indices())
     11 print(s.values())

RuntimeError: Cannot get indices on an uncoalesced tensor, please call .coalesce() first
'''
print(s.coalesce().indices())
print(s.coalesce().values())
'''
tensor(indices=tensor([[0, 1, 1],
                       [2, 0, 2]]),
       values=tensor([3, 4, 5]),
       size=(2, 3), nnz=3, layout=torch.sparse_coo)
tensor([[0, 1, 1],
        [2, 0, 2]])
tensor([3, 4, 5])
'''

 1.2.6 sparse_dim 和dense_dim

一个是index的dim,一个是value的dim

import torch

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [3, 4, 5]

s = torch.sparse_coo_tensor(i, v, (2, 3))
print(s.sparse_dim(),s.dense_dim())
#(2,0)

 

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [[3,2],[4,1],[5,3]]

s = torch.sparse_coo_tensor(i, v, (2, 3,2))
print(s.sparse_dim(),s.dense_dim())
#(2,1)

1.2.7 切片和索引

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [[3,2],[4,1],[5,3]]

s = torch.sparse_coo_tensor(i, v, (2, 3,2))
print(s)
'''
tensor(indices=tensor([[0, 1, 1],
                       [2, 0, 2]]),
       values=tensor([[3, 2],
                      [4, 1],
                      [5, 3]]),
       size=(2, 3, 2), nnz=3, layout=torch.sparse_coo)
'''

 在sparse维度(index部分)和dense部分(value部分)都可以索引

s[1]
'''
tensor(indices=tensor([[0, 1, 1],
                       [2, 0, 2]]),
       values=tensor([[3, 2],
                      [4, 1],
                      [5, 3]]),
       size=(2, 3, 2), nnz=3, layout=torch.sparse_coo)
'''

s[1,0,1]
#tensor(1)

切片只能在dense部分切 

s[1,0,1:],s[1,0,0:]
#(tensor([1]), tensor([4, 1]))

2 稀疏矩阵的基本运算

基本上都是第一个参数是sparse的,第二个是正常Tensor

先构造两个稀疏矩阵

import torch
i = torch.LongTensor([[0, 1, 1],[2, 0, 2]])   #row, col
v = torch.FloatTensor([3, 4, 5])    #data
x1=torch.sparse.FloatTensor(i, v, torch.Size([2,3]))

x1,x1.to_dense()  
'''
(tensor(indices=tensor([[0, 1, 1],
                        [2, 0, 2]]),
        values=tensor([3., 4., 5.]),
        size=(2, 3), nnz=3, layout=torch.sparse_coo),
 tensor([[0., 0., 3.],
         [4., 0., 5.]]))
'''

import torch
i = torch.LongTensor([[0, 1, 1],[1, 0, 1]])   #row, col
v = torch.FloatTensor([3, 4, 5])    #data
x2=torch.sparse.FloatTensor(i, v, torch.Size([3,2]))

x2,x2.to_dense() 
'''
(tensor(indices=tensor([[0, 1, 1],
                        [1, 0, 1]]),
        values=tensor([3., 4., 5.]),
        size=(3, 2), nnz=3, layout=torch.sparse_coo),
 tensor([[0., 3.],
         [4., 5.],
         [0., 0.]]))
'''

 2.0 不支持dense * sparse!

pytorch不支持M[strided] @ M[sparse_coo]

如果需要,可以这么整:D @ S == (S.t() @ D.t()).t()

2.1 稀疏矩阵的乘法

2.1.1 torch.mm

只支持第二个参数是dense(即dense*dense,或者sparse*dense),输出是dense

dense*dense
dense*sparse
sparse*sparse
sparse*dense

 2.1.2 torch.sparse.mm

 同样地,只支持第二个参数是dense(即dense*dense,或者sparse*dense) 

dense*dense
dense*sparse
sparse*sparse
sparse*dense

2.1.3 torch.mv

矩阵和向量的乘法,第二个也只能是dense的

import torch

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [3, 4, 5]

s = torch.sparse_coo_tensor(i, v, (2, 3))
print(s.to_dense())
'''
tensor([[0, 0, 3],
        [4, 0, 5]])
'''


t=torch.LongTensor([1,2,3])
torch.mv(s,t),s@t
'''
(tensor([ 9, 19]), tensor([ 9, 19]))
'''

2.1.4 torch.matmul

和torch.mm 类似,第二个也是只能dense

import torch

i = [[0, 1, 1],
    [2, 0, 2]]

v =  [3, 4, 5]

s = torch.sparse_coo_tensor(i, v, (2, 3))

t=torch.LongTensor([[1],[2],[3]])
torch.matmul(s,t),s@t

'''
(tensor([[ 9],
         [19]]),
 tensor([[ 9],
         [19]]))
'''

 

2.2 转置

 t()即可

x2,x2.to_dense()
'''
(tensor(indices=tensor([[0, 1, 1],
                        [1, 0, 1]]),
        values=tensor([3., 4., 5.]),
        size=(3, 2), nnz=3, layout=torch.sparse_coo),
 tensor([[0., 3.],
         [4., 5.],
         [0., 0.]]))
'''

x2.t(),x2.t().to_dense()

'''
(tensor(indices=tensor([[1, 0, 1],
                        [0, 1, 1]]),
        values=tensor([3., 4., 5.]),
        size=(2, 3), nnz=3, layout=torch.sparse_coo),
 tensor([[0., 4., 0.],
         [3., 5., 0.]]))
'''

 2.3 索引

稀疏矩阵支持整行索引,支持Sparse.matrix[row_index];

x2,x2.to_dense()
'''
(tensor(indices=tensor([[0, 1, 1],
                        [1, 0, 1]]),
        values=tensor([3., 4., 5.]),
        size=(3, 2), nnz=3, layout=torch.sparse_coo),
 tensor([[0., 3.],
         [4., 5.],
         [0., 0.]]))
'''

x2[1],x2[1].to_dense()
'''
(tensor(indices=tensor([[0, 1]]),
        values=tensor([4., 5.]),
        size=(2,), nnz=2, layout=torch.sparse_coo),
 tensor([4., 5.]))
'''

稀疏矩阵不支持具体位置位置索引Sparse.matrix[row_index,col_index]

x2[1][1],x2[1][1].to_dense()

 2.4 相加

a = torch.sparse.FloatTensor(
    torch.tensor([[0,1,2],[2,3,4]]), 
    torch.tensor([1,1,1]), 
    torch.Size([5,5]))
a.to_dense()
'''
tensor([[0, 0, 1, 0, 0],
        [0, 0, 0, 1, 0],
        [0, 0, 0, 0, 1],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0]])
'''

a1=torch.sparse.FloatTensor(
    torch.tensor([[0,3,2],[2,3,2]]), 
    torch.tensor([1,1,1]), 
    torch.Size([5,5]))
a1.to_dense()
'''
tensor([[0, 0, 1, 0, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 1, 0, 0],
        [0, 0, 0, 1, 0],
        [0, 0, 0, 0, 0]])
'''

 只支持sparse+sparse

torch.add(a,a1) ,torch.add(a,a1).to_dense()
'''
(tensor(indices=tensor([[0, 1, 2, 3, 2],
                        [2, 3, 4, 3, 2]]),
        values=tensor([2, 1, 1, 1, 1]),
        size=(5, 5), nnz=5, layout=torch.sparse_coo),
 tensor([[0, 0, 2, 0, 0],
         [0, 0, 0, 1, 0],
         [0, 0, 1, 0, 1],
         [0, 0, 0, 1, 0],
         [0, 0, 0, 0, 0]]))
'''

a.add(a1),a.add(a1).to_dense()
#同理

<think>好的,我现在要处理用户关于大模型中稀疏矩阵应用与实现的问题。首先,我需要理解用户的需求。用户提到参考了两个引用,一个是关于稀疏高效扩散模型,另一个是ALS矩阵分解模型。他们想了解大模型中稀疏矩阵的应用或实现方式。 首先,我需要回忆稀疏矩阵的基本概念。稀疏矩阵是指大部分元素为零的矩阵,这种结构在存储和计算上可以优化,减少资源消耗。大模型如GPT-3、BERT等,参数量巨大,利用稀疏矩阵可以提升效率。 接下来,结合用户提供的引用,引用[1]提到稀疏模型在推理阶段使用稀疏掩码加速计算,减少计算资源和内存占用。这可能涉及剪枝技术,去掉不重要的权重,只保留关键部分。引用[2]中的ALS矩阵分解使用稀疏矩阵处理推荐系统中的用户-物品评分矩阵,这里稀疏性是因为大部分用户没有对大部分物品评分。 然后,我需要组织回答的结构。用户要求结构清晰,分步骤解决问题。可能的思路是:先介绍稀疏矩阵的基本原理,然后在大模型中的应用场景,如参数压缩、注意力机制优化、MoE模型等,接着讨论实现方式,如剪枝、稀疏注意力、矩阵分解等,最后结合参考引用中的例子说明实际应用。 需要注意用户提到的系统级指令,比如数学表达式要用$...$,独立公式用$$...$$,并且生成相关问题。同时,回答要使用中文,正确使用LaTeX语法。例如,在解释矩阵分解时,可能需要写出数学公式,如$\mathbf{R} \approx \mathbf{P}\mathbf{Q}^T$,并用$$包裹。 还要检查是否有遗漏的应用场景或实现方式。例如,除了剪枝和注意力机制,是否有其他技术?比如知识蒸馏中的稀疏化,或者动态稀疏训练方法。另外,用户提到的两个引用分别对应不同的应用领域,扩散模型和推荐系统,需要在大模型中涵盖似的应用。 可能需要进一步确认大模型中稀疏矩阵的具体案例,比如GPT-3是否应用了稀疏注意力,或者Switch Transformer中的MoE结构如何利用稀疏性。同时,要确保引用标记正确添加,比如在提到推理加速时引用[^1],在矩阵分解时引用[^2]。 最后,生成的相关问题需要与主题紧密相关,可能涉及技术挑战、具体算法或实际应用案例。例如,稀疏矩阵如何影响模型精度,或者在不同架构中的应用差异。 总结回答的结构可能如下: 1. 稀疏矩阵的基本原理 2. 应用场景:参数压缩、注意力优化、MoE、推荐系统、扩散模型 3. 实现方式:剪枝、稀疏注意力、矩阵分解、混合专家 4. 实际案例结合引用 5. 技术挑战 6. 相关问题 需要确保每个部分自然衔接,引用正确,并且语言简洁明了。同时,数学公式正确使用LaTeX格式,如剪枝后的权重矩阵表示为$\mathbf{W}_{\text{sparse}} = \mathbf{M} \odot \mathbf{W}$,并用独立公式格式。</think>### 大模型中稀疏矩阵的实现与应用 #### 一、稀疏矩阵的基本原理 稀疏矩阵是指矩阵中绝大多数元素为零或可忽略的结构。其核心思想是通过**存储和计算的优化**,仅处理非零元素,从而降低内存占用和计算复杂度。数学上可表示为: $$ \mathbf{A} = \{(i,j,a_{ij}) \ | \ a_{ij} \neq 0\} $$ 其中非零元素占比通常小于5%。 #### 二、大模型中的核心应用场景 1. **参数压缩与加速推理** 大模型参数量巨大(如GPT-3有1750亿参数),通过剪枝技术去除冗余权重,生成稀疏矩阵。例如,权重矩阵$\mathbf{W}$剪枝后保留关键连接: $$ \mathbf{W}_{\text{sparse}} = \mathbf{M} \odot \mathbf{W} $$ 其中$\mathbf{M}$为稀疏掩码矩阵[^1]。这种方法在扩散模型中显著减少计算资源需求。 2. **注意力机制优化** 在Transformer模型中,稀疏注意力(Sparse Attention)仅计算部分位置的相关性。例如,限制每个token仅关注局部窗口或关键全局节点,将计算复杂度从$O(n^2)$降至$O(n \log n)$。 3. **混合专家(MoE)模型** 如Switch Transformer,每个输入仅激活少量专家网络,参数矩阵动态稀疏化。例如,前向传播时选择Top-2专家: $$ \text{Routing}(x) = \text{TopK}(\mathbf{W}_r x) $$ 4. **推荐系统与矩阵分解** 用户-物品评分矩阵天然稀疏(如引用[2]中的ALS模型),通过分解为低秩矩阵$\mathbf{P}$和$\mathbf{Q}$实现高效预测: $$ \mathbf{R} \approx \mathbf{P}\mathbf{Q}^T $$ #### 三、关键技术实现方式 1. **结构化剪枝与动态稀疏化** - **静态剪枝**:训练后移除低权重连接,需重新微调。 - **动态稀疏**:训练时动态调整稀疏模式(如RigL算法)。 2. **稀疏计算库支持** 使用专用库(如CuSPARSEPyTorch Sparse)加速稀疏矩阵乘法: ```python # 示例:PyTorch稀疏矩阵乘法 sparse_tensor = torch.sparse_coo_tensor(indices, values, size) result = torch.sparse.mm(sparse_tensor, dense_matrix) ``` 3. **稀疏注意力实现** ```python # 局部窗口注意力伪代码 def sparse_attention(query, key, value, window_size=64): for i in range(0, seq_len, window_size): local_block = query[i:i+window_size] @ key[i:i+window_size].T scores = softmax(local_block) output[i:i+window_size] = scores @ value[i:i+window_size] ``` #### 四、实际案例与效果 1. **稀疏扩散模型** 引用[1]中通过稀疏掩码使推理速度提升2-3倍,内存占用减少40%,适用于移动端部署。 2. **推荐系统矩阵补全** 引用[2]的ALS模型将稀疏矩阵分解为低维稠密矩阵,MAE(平均绝对误差)降低至0.85以下。 3. **语言模型MoE架构** Google的Switch Transformer在相同计算成本下,模型规模扩大7倍,推理速度保持相当。 #### 五、技术挑战与应对 1. **稀疏模式稳定性** 动态稀疏可能导致训练波动,需引入正则化约束。 2. **硬件兼容性** 非结构化稀疏难以充分利用GPU并行性,需结合结构化剪枝。 3. **精度-效率权衡** 过度剪枝可能损害模型能力,需设计重要性评估准则(如梯度幅值、Hessian敏感度)。 §§ 1. 如何量化评估稀疏化对模型精度的影响? 2. 稀疏矩阵在训练阶段如何实现反向传播? 3. 非结构化剪枝与结构化剪枝有何优劣? 4. 稀疏化技术如何与模型量化结合使用? 5. 哪些硬件架构对稀疏计算支持最佳?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UQI-LIUWJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值