PyTorch 2.2 中文官方教程(十四)(1)https://developer.aliyun.com/article/1482569
修剪教程
原文:
pytorch.org/tutorials/intermediate/pruning_tutorial.html
译者:飞龙
注意
点击这里下载完整的示例代码
最先进的深度学习技术依赖于难以部署的过度参数化模型。相反,生物神经网络已知使用高效的稀疏连接。通过识别优化的技术来通过减少模型中的参数数量来压缩模型是重要的,以便在减少内存、电池和硬件消耗的同时不牺牲准确性。这反过来使您能够在设备上部署轻量级模型,并通过设备上的私有计算来保证隐私。在研究方面,修剪被用来研究过度参数化和欠参数化网络之间学习动态的差异,研究幸运稀疏子网络和初始化(“彩票票”)的作用作为一种破坏性的神经架构搜索技术,等等。
在本教程中,您将学习如何使用torch.nn.utils.prune
来稀疏化您的神经网络,以及如何扩展它以实现自己的自定义修剪技术。
需求
"torch>=1.4.0a0+8e8a5e0"
import torch from torch import nn import torch.nn.utils.prune as prune import torch.nn.functional as F
创建一个模型
在本教程中,我们使用来自 LeCun 等人的 1998 年的LeNet架构。
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") class LeNet(nn.Module): def __init__(self): super(LeNet, self).__init__() # 1 input image channel, 6 output channels, 5x5 square conv kernel self.conv1 = nn.Conv2d(1, 6, 5) self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 5 * 5, 120) # 5x5 image dimension self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) x = F.max_pool2d(F.relu(self.conv2(x)), 2) x = x.view(-1, int(x.nelement() / x.shape[0])) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x model = LeNet().to(device=device)
检查一个模块
让我们检查我们 LeNet 模型中的(未修剪的)conv1
层。它将包含两个参数weight
和bias
,目前没有缓冲区。
module = model.conv1 print(list(module.named_parameters()))
[('weight', Parameter containing: tensor([[[[ 0.1529, 0.1660, -0.0469, 0.1837, -0.0438], [ 0.0404, -0.0974, 0.1175, 0.1763, -0.1467], [ 0.1738, 0.0374, 0.1478, 0.0271, 0.0964], [-0.0282, 0.1542, 0.0296, -0.0934, 0.0510], [-0.0921, -0.0235, -0.0812, 0.1327, -0.1579]]], [[[-0.0922, -0.0565, -0.1203, 0.0189, -0.1975], [ 0.1806, -0.1699, 0.1544, 0.0333, -0.0649], [ 0.1236, 0.0312, 0.1616, 0.0219, -0.0631], [ 0.0537, -0.0542, 0.0842, 0.1786, 0.1156], [-0.0874, 0.1155, 0.0358, 0.1016, -0.1219]]], [[[-0.1980, -0.0773, -0.1534, 0.1641, 0.0576], [ 0.0828, 0.0633, -0.0035, 0.1565, -0.1421], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0667, 0.1925, -0.1651, -0.1984]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.1033, -0.1363, 0.1061, -0.0808, 0.1214], [-0.0475, 0.1144, -0.1554, -0.1009, 0.0610], [ 0.0423, -0.0510, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0675, -0.0709, -0.1935]]], [[[-0.1145, 0.0500, -0.0264, -0.1452, 0.0047], [-0.1366, -0.1697, -0.1101, -0.1750, -0.1273], [ 0.1999, 0.0378, 0.0616, -0.1865, -0.1314], [-0.0666, 0.0313, -0.1760, -0.0862, -0.1197], [ 0.0006, -0.0744, -0.0139, -0.1355, -0.1373]]], [[[-0.1167, -0.0685, -0.1579, 0.1677, -0.0397], [ 0.1721, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.1988, 0.0572, -0.0437], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.1033, 0.1615, 0.1822, -0.1586]]]], device='cuda:0', requires_grad=True)), ('bias', Parameter containing: tensor([ 0.0503, -0.0860, -0.0219, -0.1497, 0.1822, -0.1468], device='cuda:0', requires_grad=True))]
print(list(module.named_buffers()))
[]
修剪一个模块
要修剪一个模块(在这个例子中,是我们的 LeNet 架构中的conv1
层),首先在torch.nn.utils.prune
中选择一个修剪技术(或者实现自己的方法,通过继承BasePruningMethod
)。然后,指定要在该模块内修剪的模块和参数的名称。最后,使用所选修剪技术所需的适当关键字参数,指定修剪参数。
在这个例子中,我们将在conv1
层的名为weight
的参数中随机修剪 30%的连接。模块作为函数的第一个参数传递;name
使用其字符串标识符在该模块内标识参数;amount
指示要修剪的连接的百分比(如果是 0 和 1 之间的浮点数),或要修剪的连接的绝对数量(如果是非负整数)。
prune.random_unstructured(module, name="weight", amount=0.3)
Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
修剪通过从参数中删除weight
并用一个名为weight_orig
的新参数替换它(即将初始参数name
附加"_orig"
)。weight_orig
存储张量的未修剪版本。bias
没有被修剪,因此它将保持不变。
print(list(module.named_parameters()))
[('bias', Parameter containing: tensor([ 0.0503, -0.0860, -0.0219, -0.1497, 0.1822, -0.1468], device='cuda:0', requires_grad=True)), ('weight_orig', Parameter containing: tensor([[[[ 0.1529, 0.1660, -0.0469, 0.1837, -0.0438], [ 0.0404, -0.0974, 0.1175, 0.1763, -0.1467], [ 0.1738, 0.0374, 0.1478, 0.0271, 0.0964], [-0.0282, 0.1542, 0.0296, -0.0934, 0.0510], [-0.0921, -0.0235, -0.0812, 0.1327, -0.1579]]], [[[-0.0922, -0.0565, -0.1203, 0.0189, -0.1975], [ 0.1806, -0.1699, 0.1544, 0.0333, -0.0649], [ 0.1236, 0.0312, 0.1616, 0.0219, -0.0631], [ 0.0537, -0.0542, 0.0842, 0.1786, 0.1156], [-0.0874, 0.1155, 0.0358, 0.1016, -0.1219]]], [[[-0.1980, -0.0773, -0.1534, 0.1641, 0.0576], [ 0.0828, 0.0633, -0.0035, 0.1565, -0.1421], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0667, 0.1925, -0.1651, -0.1984]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.1033, -0.1363, 0.1061, -0.0808, 0.1214], [-0.0475, 0.1144, -0.1554, -0.1009, 0.0610], [ 0.0423, -0.0510, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0675, -0.0709, -0.1935]]], [[[-0.1145, 0.0500, -0.0264, -0.1452, 0.0047], [-0.1366, -0.1697, -0.1101, -0.1750, -0.1273], [ 0.1999, 0.0378, 0.0616, -0.1865, -0.1314], [-0.0666, 0.0313, -0.1760, -0.0862, -0.1197], [ 0.0006, -0.0744, -0.0139, -0.1355, -0.1373]]], [[[-0.1167, -0.0685, -0.1579, 0.1677, -0.0397], [ 0.1721, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.1988, 0.0572, -0.0437], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.1033, 0.1615, 0.1822, -0.1586]]]], device='cuda:0', requires_grad=True))]
上面选择的修剪技术生成的修剪蒙版被保存为一个名为weight_mask
的模块缓冲区(即将初始参数name
附加"_mask"
)。
print(list(module.named_buffers()))
[('weight_mask', tensor([[[[1., 1., 1., 1., 1.], [1., 0., 1., 1., 1.], [1., 0., 0., 1., 1.], [1., 0., 1., 1., 1.], [1., 0., 0., 1., 1.]]], [[[1., 1., 1., 0., 1.], [1., 1., 1., 1., 1.], [0., 1., 1., 1., 0.], [1., 1., 0., 1., 0.], [0., 1., 0., 1., 1.]]], [[[1., 0., 0., 0., 1.], [1., 0., 1., 1., 0.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 0., 1., 1., 0.]]], [[[1., 1., 1., 1., 1.], [0., 1., 1., 1., 0.], [1., 1., 1., 0., 1.], [0., 0., 1., 1., 1.], [1., 1., 0., 1., 1.]]], [[[1., 0., 1., 1., 1.], [1., 1., 0., 0., 0.], [1., 1., 0., 0., 0.], [0., 1., 1., 0., 1.], [1., 0., 0., 0., 1.]]], [[[1., 0., 1., 0., 1.], [0., 1., 1., 1., 1.], [1., 1., 0., 1., 0.], [1., 1., 1., 1., 1.], [1., 0., 0., 1., 1.]]]], device='cuda:0'))]
为了使前向传播无需修改工作,weight
属性需要存在。在torch.nn.utils.prune
中实现的修剪技术计算权重的修剪版本(通过将蒙版与原始参数组合)并将它们存储在属性weight
中。请注意,这不再是module
的参数,现在只是一个属性。
print(module.weight)
tensor([[[[ 0.1529, 0.1660, -0.0469, 0.1837, -0.0438], [ 0.0404, -0.0000, 0.1175, 0.1763, -0.1467], [ 0.1738, 0.0000, 0.0000, 0.0271, 0.0964], [-0.0282, 0.0000, 0.0296, -0.0934, 0.0510], [-0.0921, -0.0000, -0.0000, 0.1327, -0.1579]]], [[[-0.0922, -0.0565, -0.1203, 0.0000, -0.1975], [ 0.1806, -0.1699, 0.1544, 0.0333, -0.0649], [ 0.0000, 0.0312, 0.1616, 0.0219, -0.0000], [ 0.0537, -0.0542, 0.0000, 0.1786, 0.0000], [-0.0000, 0.1155, 0.0000, 0.1016, -0.1219]]], [[[-0.1980, -0.0000, -0.0000, 0.0000, 0.0576], [ 0.0828, 0.0000, -0.0035, 0.1565, -0.0000], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0000, 0.1925, -0.1651, -0.0000]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.0000, -0.1363, 0.1061, -0.0808, 0.0000], [-0.0475, 0.1144, -0.1554, -0.0000, 0.0610], [ 0.0000, -0.0000, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0000, -0.0709, -0.1935]]], [[[-0.1145, 0.0000, -0.0264, -0.1452, 0.0047], [-0.1366, -0.1697, -0.0000, -0.0000, -0.0000], [ 0.1999, 0.0378, 0.0000, -0.0000, -0.0000], [-0.0000, 0.0313, -0.1760, -0.0000, -0.1197], [ 0.0006, -0.0000, -0.0000, -0.0000, -0.1373]]], [[[-0.1167, -0.0000, -0.1579, 0.0000, -0.0397], [ 0.0000, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.0000, 0.0572, -0.0000], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.0000, 0.0000, 0.1822, -0.1586]]]], device='cuda:0', grad_fn=<MulBackward0>)
最后,在每次前向传播之前应用修剪,使用 PyTorch 的forward_pre_hooks
。具体来说,当module
被修剪时,就像我们在这里所做的那样,它将为与之关联的每个参数获取一个forward_pre_hook
。在这种情况下,因为我们目前只修剪了名为weight
的原始参数,所以只有一个钩子存在。
print(module._forward_pre_hooks)
OrderedDict([(0, <torch.nn.utils.prune.RandomUnstructured object at 0x7f4c36e10e50>)])
为了完整起见,我们现在也可以修剪bias
,以查看module
的参数、缓冲区、hook 和属性如何变化。为了尝试另一种修剪技术,这里我们通过 L1 范数在偏置中修剪最小的 3 个条目,如l1_unstructured
修剪函数中实现的那样。
prune.l1_unstructured(module, name="bias", amount=3)
Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
我们现在期望命名参数包括weight_orig
(之前的)和bias_orig
。缓冲区将包括weight_mask
和bias_mask
。这两个张量的修剪版本将存在作为模块属性,并且模块现在将有两个forward_pre_hooks
。
print(list(module.named_parameters()))
[('weight_orig', Parameter containing: tensor([[[[ 0.1529, 0.1660, -0.0469, 0.1837, -0.0438], [ 0.0404, -0.0974, 0.1175, 0.1763, -0.1467], [ 0.1738, 0.0374, 0.1478, 0.0271, 0.0964], [-0.0282, 0.1542, 0.0296, -0.0934, 0.0510], [-0.0921, -0.0235, -0.0812, 0.1327, -0.1579]]], [[[-0.0922, -0.0565, -0.1203, 0.0189, -0.1975], [ 0.1806, -0.1699, 0.1544, 0.0333, -0.0649], [ 0.1236, 0.0312, 0.1616, 0.0219, -0.0631], [ 0.0537, -0.0542, 0.0842, 0.1786, 0.1156], [-0.0874, 0.1155, 0.0358, 0.1016, -0.1219]]], [[[-0.1980, -0.0773, -0.1534, 0.1641, 0.0576], [ 0.0828, 0.0633, -0.0035, 0.1565, -0.1421], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0667, 0.1925, -0.1651, -0.1984]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.1033, -0.1363, 0.1061, -0.0808, 0.1214], [-0.0475, 0.1144, -0.1554, -0.1009, 0.0610], [ 0.0423, -0.0510, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0675, -0.0709, -0.1935]]], [[[-0.1145, 0.0500, -0.0264, -0.1452, 0.0047], [-0.1366, -0.1697, -0.1101, -0.1750, -0.1273], [ 0.1999, 0.0378, 0.0616, -0.1865, -0.1314], [-0.0666, 0.0313, -0.1760, -0.0862, -0.1197], [ 0.0006, -0.0744, -0.0139, -0.1355, -0.1373]]], [[[-0.1167, -0.0685, -0.1579, 0.1677, -0.0397], [ 0.1721, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.1988, 0.0572, -0.0437], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.1033, 0.1615, 0.1822, -0.1586]]]], device='cuda:0', requires_grad=True)), ('bias_orig', Parameter containing: tensor([ 0.0503, -0.0860, -0.0219, -0.1497, 0.1822, -0.1468], device='cuda:0', requires_grad=True))]
print(list(module.named_buffers()))
[('weight_mask', tensor([[[[1., 1., 1., 1., 1.], [1., 0., 1., 1., 1.], [1., 0., 0., 1., 1.], [1., 0., 1., 1., 1.], [1., 0., 0., 1., 1.]]], [[[1., 1., 1., 0., 1.], [1., 1., 1., 1., 1.], [0., 1., 1., 1., 0.], [1., 1., 0., 1., 0.], [0., 1., 0., 1., 1.]]], [[[1., 0., 0., 0., 1.], [1., 0., 1., 1., 0.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 0., 1., 1., 0.]]], [[[1., 1., 1., 1., 1.], [0., 1., 1., 1., 0.], [1., 1., 1., 0., 1.], [0., 0., 1., 1., 1.], [1., 1., 0., 1., 1.]]], [[[1., 0., 1., 1., 1.], [1., 1., 0., 0., 0.], [1., 1., 0., 0., 0.], [0., 1., 1., 0., 1.], [1., 0., 0., 0., 1.]]], [[[1., 0., 1., 0., 1.], [0., 1., 1., 1., 1.], [1., 1., 0., 1., 0.], [1., 1., 1., 1., 1.], [1., 0., 0., 1., 1.]]]], device='cuda:0')), ('bias_mask', tensor([0., 0., 0., 1., 1., 1.], device='cuda:0'))]
print(module.bias)
tensor([ 0.0000, -0.0000, -0.0000, -0.1497, 0.1822, -0.1468], device='cuda:0', grad_fn=<MulBackward0>)
print(module._forward_pre_hooks)
OrderedDict([(0, <torch.nn.utils.prune.RandomUnstructured object at 0x7f4c36e10e50>), (1, <torch.nn.utils.prune.L1Unstructured object at 0x7f4c632815d0>)])
迭代修剪
模块中的同一参数可以多次修剪,各个修剪调用的效果等于串行应用的各个掩码的组合。新掩码与旧掩码的组合由PruningContainer
的compute_mask
方法处理。
例如,假设我们现在想要进一步修剪module.weight
,这次使用张量的第 0 轴(第 0 轴对应于卷积层的输出通道,并且对于conv1
,维度为 6)上的结构化修剪,基于通道的 L2 范数。这可以使用ln_structured
函数实现,其中n=2
和dim=0
。
prune.ln_structured(module, name="weight", amount=0.5, n=2, dim=0) # As we can verify, this will zero out all the connections corresponding to # 50% (3 out of 6) of the channels, while preserving the action of the # previous mask. print(module.weight)
tensor([[[[ 0.0000, 0.0000, -0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000], [-0.0000, 0.0000, 0.0000, -0.0000, 0.0000], [-0.0000, -0.0000, -0.0000, 0.0000, -0.0000]]], [[[-0.0000, -0.0000, -0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, 0.0000], [-0.0000, 0.0000, 0.0000, 0.0000, -0.0000]]], [[[-0.1980, -0.0000, -0.0000, 0.0000, 0.0576], [ 0.0828, 0.0000, -0.0035, 0.1565, -0.0000], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0000, 0.1925, -0.1651, -0.0000]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.0000, -0.1363, 0.1061, -0.0808, 0.0000], [-0.0475, 0.1144, -0.1554, -0.0000, 0.0610], [ 0.0000, -0.0000, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0000, -0.0709, -0.1935]]], [[[-0.0000, 0.0000, -0.0000, -0.0000, 0.0000], [-0.0000, -0.0000, -0.0000, -0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, -0.0000, -0.0000], [-0.0000, 0.0000, -0.0000, -0.0000, -0.0000], [ 0.0000, -0.0000, -0.0000, -0.0000, -0.0000]]], [[[-0.1167, -0.0000, -0.1579, 0.0000, -0.0397], [ 0.0000, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.0000, 0.0572, -0.0000], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.0000, 0.0000, 0.1822, -0.1586]]]], device='cuda:0', grad_fn=<MulBackward0>)
相应的 hook 现在将是torch.nn.utils.prune.PruningContainer
类型,并将存储应用于weight
参数的修剪历史。
for hook in module._forward_pre_hooks.values(): if hook._tensor_name == "weight": # select out the correct hook break print(list(hook)) # pruning history in the container
[<torch.nn.utils.prune.RandomUnstructured object at 0x7f4c36e10e50>, <torch.nn.utils.prune.LnStructured object at 0x7f4c63282c50>]
序列化修剪模型
所有相关张量,包括掩码缓冲区和用于计算修剪张量的原始参数都存储在模型的state_dict
中,因此如果需要,可以轻松序列化和保存。
print(model.state_dict().keys())
odict_keys(['conv1.weight_orig', 'conv1.bias_orig', 'conv1.weight_mask', 'conv1.bias_mask', 'conv2.weight', 'conv2.bias', 'fc1.weight', 'fc1.bias', 'fc2.weight', 'fc2.bias', 'fc3.weight', 'fc3.bias'])
移除修剪重新参数化
要使修剪永久化,删除关于weight_orig
和weight_mask
的重新参数化,并删除forward_pre_hook
,我们可以使用torch.nn.utils.prune
中的remove
功能。请注意,这不会撤消修剪,就好像从未发生过一样。它只是使其永久化,通过将参数weight
重新分配给模型参数,以其修剪版本。
在移除重新参数化之前:
print(list(module.named_parameters()))
[('weight_orig', Parameter containing: tensor([[[[ 0.1529, 0.1660, -0.0469, 0.1837, -0.0438], [ 0.0404, -0.0974, 0.1175, 0.1763, -0.1467], [ 0.1738, 0.0374, 0.1478, 0.0271, 0.0964], [-0.0282, 0.1542, 0.0296, -0.0934, 0.0510], [-0.0921, -0.0235, -0.0812, 0.1327, -0.1579]]], [[[-0.0922, -0.0565, -0.1203, 0.0189, -0.1975], [ 0.1806, -0.1699, 0.1544, 0.0333, -0.0649], [ 0.1236, 0.0312, 0.1616, 0.0219, -0.0631], [ 0.0537, -0.0542, 0.0842, 0.1786, 0.1156], [-0.0874, 0.1155, 0.0358, 0.1016, -0.1219]]], [[[-0.1980, -0.0773, -0.1534, 0.1641, 0.0576], [ 0.0828, 0.0633, -0.0035, 0.1565, -0.1421], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0667, 0.1925, -0.1651, -0.1984]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.1033, -0.1363, 0.1061, -0.0808, 0.1214], [-0.0475, 0.1144, -0.1554, -0.1009, 0.0610], [ 0.0423, -0.0510, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0675, -0.0709, -0.1935]]], [[[-0.1145, 0.0500, -0.0264, -0.1452, 0.0047], [-0.1366, -0.1697, -0.1101, -0.1750, -0.1273], [ 0.1999, 0.0378, 0.0616, -0.1865, -0.1314], [-0.0666, 0.0313, -0.1760, -0.0862, -0.1197], [ 0.0006, -0.0744, -0.0139, -0.1355, -0.1373]]], [[[-0.1167, -0.0685, -0.1579, 0.1677, -0.0397], [ 0.1721, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.1988, 0.0572, -0.0437], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.1033, 0.1615, 0.1822, -0.1586]]]], device='cuda:0', requires_grad=True)), ('bias_orig', Parameter containing: tensor([ 0.0503, -0.0860, -0.0219, -0.1497, 0.1822, -0.1468], device='cuda:0', requires_grad=True))]
print(list(module.named_buffers()))
[('weight_mask', tensor([[[[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]]], [[[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]]], [[[1., 0., 0., 0., 1.], [1., 0., 1., 1., 0.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 0., 1., 1., 0.]]], [[[1., 1., 1., 1., 1.], [0., 1., 1., 1., 0.], [1., 1., 1., 0., 1.], [0., 0., 1., 1., 1.], [1., 1., 0., 1., 1.]]], [[[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]]], [[[1., 0., 1., 0., 1.], [0., 1., 1., 1., 1.], [1., 1., 0., 1., 0.], [1., 1., 1., 1., 1.], [1., 0., 0., 1., 1.]]]], device='cuda:0')), ('bias_mask', tensor([0., 0., 0., 1., 1., 1.], device='cuda:0'))]
print(module.weight)
tensor([[[[ 0.0000, 0.0000, -0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000], [-0.0000, 0.0000, 0.0000, -0.0000, 0.0000], [-0.0000, -0.0000, -0.0000, 0.0000, -0.0000]]], [[[-0.0000, -0.0000, -0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, 0.0000], [-0.0000, 0.0000, 0.0000, 0.0000, -0.0000]]], [[[-0.1980, -0.0000, -0.0000, 0.0000, 0.0576], [ 0.0828, 0.0000, -0.0035, 0.1565, -0.0000], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0000, 0.1925, -0.1651, -0.0000]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.0000, -0.1363, 0.1061, -0.0808, 0.0000], [-0.0475, 0.1144, -0.1554, -0.0000, 0.0610], [ 0.0000, -0.0000, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0000, -0.0709, -0.1935]]], [[[-0.0000, 0.0000, -0.0000, -0.0000, 0.0000], [-0.0000, -0.0000, -0.0000, -0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, -0.0000, -0.0000], [-0.0000, 0.0000, -0.0000, -0.0000, -0.0000], [ 0.0000, -0.0000, -0.0000, -0.0000, -0.0000]]], [[[-0.1167, -0.0000, -0.1579, 0.0000, -0.0397], [ 0.0000, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.0000, 0.0572, -0.0000], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.0000, 0.0000, 0.1822, -0.1586]]]], device='cuda:0', grad_fn=<MulBackward0>)
移除重新参数化后:
prune.remove(module, 'weight') print(list(module.named_parameters()))
[('bias_orig', Parameter containing: tensor([ 0.0503, -0.0860, -0.0219, -0.1497, 0.1822, -0.1468], device='cuda:0', requires_grad=True)), ('weight', Parameter containing: tensor([[[[ 0.0000, 0.0000, -0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000], [-0.0000, 0.0000, 0.0000, -0.0000, 0.0000], [-0.0000, -0.0000, -0.0000, 0.0000, -0.0000]]], [[[-0.0000, -0.0000, -0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, 0.0000, -0.0000], [ 0.0000, -0.0000, 0.0000, 0.0000, 0.0000], [-0.0000, 0.0000, 0.0000, 0.0000, -0.0000]]], [[[-0.1980, -0.0000, -0.0000, 0.0000, 0.0576], [ 0.0828, 0.0000, -0.0035, 0.1565, -0.0000], [ 0.0126, -0.1365, 0.0617, -0.0689, 0.0613], [-0.0417, 0.1659, -0.1185, -0.1193, -0.1193], [ 0.1799, 0.0000, 0.1925, -0.1651, -0.0000]]], [[[-0.1565, -0.1345, 0.0810, 0.0716, 0.1662], [-0.0000, -0.1363, 0.1061, -0.0808, 0.0000], [-0.0475, 0.1144, -0.1554, -0.0000, 0.0610], [ 0.0000, -0.0000, 0.1192, 0.1360, -0.1450], [-0.1068, 0.1831, -0.0000, -0.0709, -0.1935]]], [[[-0.0000, 0.0000, -0.0000, -0.0000, 0.0000], [-0.0000, -0.0000, -0.0000, -0.0000, -0.0000], [ 0.0000, 0.0000, 0.0000, -0.0000, -0.0000], [-0.0000, 0.0000, -0.0000, -0.0000, -0.0000], [ 0.0000, -0.0000, -0.0000, -0.0000, -0.0000]]], [[[-0.1167, -0.0000, -0.1579, 0.0000, -0.0397], [ 0.0000, 0.0623, -0.1694, 0.1384, -0.0550], [-0.0767, -0.1660, -0.0000, 0.0572, -0.0000], [ 0.0779, -0.1641, 0.1485, -0.1468, -0.0345], [ 0.0418, 0.0000, 0.0000, 0.1822, -0.1586]]]], device='cuda:0', requires_grad=True))]
print(list(module.named_buffers()))
[('bias_mask', tensor([0., 0., 0., 1., 1., 1.], device='cuda:0'))]
PyTorch 2.2 中文官方教程(十四)(3)https://developer.aliyun.com/article/1482574