# mypy: 允许未类型化定义
r剪枝方法。
导入
数字
来自 abc
导入 ABC,
抽象方法
来自 collections.abc
导入
迭代器
导入
火炬
[文档]
类
基础剪枝方法(ABC):
r抽象基类,用于创建新的剪枝技术。
提供定制所需的骨架,需要覆盖方法
例如::meth:`compute_mask` 和 :meth:`apply`。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
_tensor_name: 字符串
def __调用__(
自身,
模块,
输入):
r将掩码乘入原始张量并存储结果。
将掩码(存储在 `module[name + '_mask']`)乘入
原始张量(存储在 `module[name + '_orig']`)
使用 :meth:`apply_mask` 将结果存储到 `module[name]` 中。
参数:
模块(nn.Module):包含要剪枝张量的模块
输入:未使用。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
setattr(模块,
自身._tensor_name,
自身.
应用掩码(
模块))
[文档] @abstractmethod
def compute_mask(self, t, default_mask):
r"""计算并返回输入张量 ``t`` 的掩码。"""
从一个基本的 `default_mask`(如果张量尚未被剪枝的话)开始,生成一个随机掩码
应用到 `default_mask` 上,具体方法根据剪枝方法配方
生成一个随机掩码,根据特定的剪枝方法
配方来应用。
Args:
t (torch.Tensor): 表示剪枝参数重要性的张量。
default_mask (torch.Tensor): 基于之前剪枝的基掩码。
previous_pruning (torch.Tensor): 上次剪枝的掩码。
在应用新掩码后需要遵守的迭代次数。
与`t`相同的维度。
返回:
mask (torch.Tensor):应用于`t`的掩码,与`t`具有相同的维度。
"""
[文档] def apply_mask(self, module):
简单处理被剪枝的参数与生成的掩码之间的乘法。
从模块中获取掩码和原始张量。
返回张量的修剪版本。
参数:
模块(nn.Module):包含要剪枝张量的模块
返回:
pruned_tensor (torch.Tensor): 输入张量的剪枝版本
"""
# 执行乘法之前,需要计算掩码,
# 因此,剪枝方法必须知道它正在操作哪个张量
assert (
self._tensor_name 不为 None
), f"模块 {module} 需要被剪枝" # 这在 apply() 中设置
mask = getattr(module, self._tensor_name + "_mask")
orig = getattr(module, self._tensor_name + "_orig")
pruned_tensor = mask.to(dtype=orig.dtype) * orig
return pruned_tensor
[文档] @classmethod
def 应用(
类,
模块,
名称, *
参数,
重要性得分=
无, **kwargs):
r动态添加剪枝和张量的重新参数化。
添加了前置钩子,允许动态剪枝
张量在原始张量意义上的重新参数化
并且剪枝掩码。
参数:
模块(nn.Module):包含要剪枝张量的模块
name(字符串):在 ``module`` 中作为剪枝参数的参数名称
将起作用。
args:传递给子类的参数
class:`BasePruningMethod`
importance_scores (torch.Tensor):重要性分数张量(用于计算剪枝掩码)
其形状与模块参数相同,用于计算剪枝掩码。
该张量中的值表示该参数的重要性。
被修剪参数中的对应元素。
如果未指定或为 None,将使用该参数。
kwargs:传递给子类的关键字参数。
class:`BasePruningMethod`
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
def _get_composite_method(类,
模块,
名称, *
参数, **kwargs):
# 检查是否已经应用了剪枝方法
# 如果已经应用了 `module[name]`,则将其存储在 `old_method` 中。
旧方法 = None
找到 = 0
# 实际上应该只有一个 hook.name == name 的钩子
# 使用 `found` 断言这一点
要删除的钩子 = []
为 k,
钩子
在
模块.
_前向预处理钩子.
项目():
# 如果存在,取现有事物,移除钩子,然后
# 正常进行事物
如果 isinstance(hook,
基础剪枝方法)
和 hook._tensor_name ==
名称:
旧方法 =
钩子
移除钩子.
追加(k)
找到 += 1
断言 (
找到
≤ 1
), f"避免向同一模块的 tensor 添加多个剪枝钩"\
同一 tensor{
名称}
的模块{
模块}
。使用剪枝容器。
为 k
在
移除钩子:
删除
模块.
_前向预处理钩子[k]
# 从头开始应用新的剪枝方法,或者基于上一个方法。
# 或者新的剪枝。
方法 =
类(*
参数, **kwargs)
# 新的剪枝
# 剪枝方法要记住它被应用到哪个张量上
方法._tensor_name =
名称
# 如果存在 old_method,则将 `methods` 与 `old_method` 结合
如果
旧方法
是 not
无:
# 表示存在钩子
# 如果钩子已经是剪枝容器,只需将
# 新的剪枝方法添加到容器中
如果 isinstance(
旧方法, PruningContainer):
旧方法.
添加剪枝方法(
方法)
方法 =
旧方法
将旧方法重命名为 method
如果钩子只是一个单一的剪枝方法,创建一个容器
将旧剪枝方法和新方法添加到容器中
elif isinstance(旧方法,
基础剪枝方法):
容器 = PruningContainer(
旧方法)
# 让剪枝方法记住其张量的名称
# setattr(container, '_tensor_name', name)
容器.
添加剪枝方法(
方法)
方法 =
容器
# 重命名 container --> 方法
返回
方法
方法 = _get_composite_method(
类,
模块,
名称, *
参数, **kwargs)
# 在此阶段我们还没有前向钩子,但我们可能会有
# 如果应用了另一种剪枝方法(在这种情况下,`method` 将是剪枝容器
# 而不是简单的剪枝方法)。
#)。
对模块的名为 `name` 的张量进行剪枝,
从它在此迭代之前所处的状态开始,
基于重要性分数计算剪枝掩码。
原始 = getattr(
模块,
名称)
如果
重要性得分
是 not
无:
断言 (
重要性得分.
形状 ==
原始.
形状
), f"重要性得分应与参数具有相同的形状"{
名称}
的{
模块}"
否则:
重要性得分 =
原始
# 如果这是第一次应用剪枝,请注意移动
将原始张量复制到一个名为 name + '_orig' 的新参数中
删除原始参数
如果 not isinstance(
方法, PruningContainer):
将 `module[name]` 复制到 `module[name + '_orig']`
模块.
注册参数(
名称 +
"_原",
原始)
# 临时删除 `module[name]`
删除
模块.
参数[
名称]
默认掩码 =
火炬.
喜欢的(
原始)
# 临时
# 如果这不是第一次进行剪枝,那么以上所有内容
# 在之前的剪枝迭代中已经执行过,所以没问题
# 可以继续
否则:
默认掩码 = (
getattr(模块,
名称 +
_mask)
.detach()
.克隆(
内存格式=
火炬.
连续格式)
)
因为如果对掩码有任何错误,请使用 try/except
等计算等,您可能需要回滚。
try:
获取最终掩码,根据特定方法计算得出
遮罩 =
方法.
计算掩码(
重要性得分,
默认掩码=
默认掩码)
通过将掩码保存到 `module[name + '_mask']` 来重新参数化...
模块.
注册缓冲区(
名称 +
_mask,
面具)
# ...并将新的剪枝张量赋值给`module[name]`
setattr(模块,
名称,
方法.
应用掩码(
模块))
# 通过钩子将剪枝方法关联到模块
在每次 forward()之前计算函数(通过运行编译)
模块.
注册前向钩子(
方法)
除了
异常
作为 e:
如果 not isinstance(
方法, PruningContainer):
原始 = getattr(
模块,
名称 +
"_原")
模块.
注册参数(
名称,
原始)
删除
模块.
参数[
名称 +
"_原"]
提升 e
返回
方法
[文档] def prune(self, t, default_mask=None, importance_scores=None):
计算并返回输入张量 ``t`` 的剪枝版本。
根据在 :meth:`compute_mask` 中指定的剪枝规则。
参数:
t (torch.Tensor):要剪枝的张量(与 ``default_mask`` 维度相同)
``default_mask``)。
importance_scores (torch.Tensor):重要性得分张量(与 ``t`` 维度相同),用于计算剪枝 ``t`` 的掩码。
importance_scores (torch.Tensor):重要性得分张量(与 ``t`` 维度相同),用于计算剪枝 ``t`` 的掩码。
这个张量中的值表示其重要性
对应于正在剪枝的`t`中的元素。
如果未指定或为 None,将使用张量`t`代替。
默认掩码(torch.Tensor,可选):来自先前剪枝的掩码
迭代,如果有。在确定应该作用在张量哪一部分进行剪枝时需要考虑。
指定剪枝应该作用在张量的哪一部分。如果为 None,则默认为全一的掩码。
默认为全一的掩码。
返回:
张量 ``t`` 的修剪版本。
"""
如果 importance_scores 不为 None:
断言 (
importance_scores.shape == t.shape
), "importance_scores 应该与张量 t 具有相同的形状"
else:
importance_scores = t
default_mask = default_mask if default_mask is not None else torch.ones_like(t)
return t * self.compute_mask(importance_scores, default_mask=default_mask)
[文档] def remove(self, module):
r"""从模块中移除剪枝重新参数化。"""
被修剪的参数名为 ``name`` 将永久被修剪,
并且名为 ``name+'_orig'`` 的参数将从参数列表中移除。
同样,名为 ``name+'_mask'`` 的缓冲区也将被移除。
注意:
自我修剪不可撤销或逆转!
"""
在从张量中移除修剪之前,它必须已经被应用
断言(
self._tensor_name 不为 None
), f"模块 {module} 必须在移除剪枝之前进行剪枝" # 这在 apply() 中设置
# 更新 module[name] 到最新的训练权重
weight = self.apply_mask(module) # 带掩码的权重
删除并重置
如果 hasattr(module, self._tensor_name):
删除 module 的 self._tensor_name 属性
orig = module._parameters[self._tensor_name + "_orig"]
原始数据 = 权重数据
删除 module._parameters[self._tensor_name + "_orig"]
删除 module._buffers[self._tensor_name + "_mask"]
将 setattr(module, self._tensor_name, orig) 赋值给 module
[文档]
类 PruningContainer(
基础剪枝方法):
"包含一系列剪枝方法的容器,用于迭代剪枝。
记录剪枝方法应用的顺序并处理
结合连续的剪枝调用。
接受一个 BasePruningMethod 的实例或一个 BasePruningMethod 的迭代器作为参数。
它们。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
def 初始化(
自身, *
参数):
自身.
_剪枝方法:
元组[
基础剪枝方法, ...] = ()
如果 not isinstance(
参数,
迭代器):
# 只有 1 项
自身._tensor_name =
参数._tensor_name
自身.
添加剪枝方法(
参数)
elif 长度(
参数) == 1:
# 元组中只有 1 个元素
自身._tensor_name =
参数[0]._tensor_name
自身.
添加剪枝方法(
参数[0])
否则:
# 从列表或其他可迭代对象手动构建(或无参数)
为
方法
在
参数:
自身.
添加剪枝方法(
方法)
[文档] def 添加剪枝方法(self, 方法):
r"""向容器添加子剪枝 ``方法``。
参数:
方法(BasePruningMethod 的子类):子节点剪枝方法
需要添加到容器中。
"""
# 检查是否已将剪枝方法添加到容器中
如果不是 BasePruningMethod 的实例且 method 不是 None:
则抛出 TypeError 异常(f"{type(method)}不是 BasePruningMethod 的子类")
elif method 不是 None 且 self._tensor_name 不等于 method._tensor_name:
则抛出 ValueError 异常(
只能添加作用于 "
该参数名为'{self._tensor_name}'的剪枝容器{self}。
发现 '{method._tensor_name}'
)
# 如果所有检查通过,则添加到_pruning_methods 元组中
self._pruning_methods += (method,) # 忽略操作符类型
def __len__(自身):
返回
长度(
自身.
_剪枝方法)
def __iter__(自身):
返回
迭代(
自身.
_剪枝方法)
def __getitem__(自身,
索引):
返回
自身.
_剪枝方法[
索引]
[文档] def
计算掩码(
自身, t,
默认掩码):
r应用最新的 ``方法``,通过计算新的部分掩码,并将其与 ``default_mask`` 结合返回。
新的局部掩码应计算在未被 `default_mask` 清零的条目或通道上
的哪些部分。新掩码将从张量 `t` 的哪些部分计算取决于 `PRUNING_TYPE`(由类型处理器处理):
依赖于 `PRUNING_TYPE`(由类型处理器处理):
有关张量 `t` 的新掩码将计算哪些部分取决于 `PRUNING_TYPE`(由类型处理器处理):
* 对于 'unstructured',掩码将从非掩码条目列表中计算得出
* 对于 'structured',掩码将从张量中的非掩码通道计算得出
* 对于 'unstructured',掩码将从非掩码条目列表中计算得出
* 对于 'structured',掩码将从张量中的非掩码通道计算得出
* 对于 'global',掩码将在所有条目上计算。
参数:
t (torch.Tensor):表示剪枝参数的张量。
(与 ``default_mask`` 维度相同)。
default_mask (torch.Tensor):来自先前剪枝迭代的掩码。
返回:
mask (torch.Tensor):新的 mask,结合了效果
的 `default_mask` 和当前的新掩码
修剪 `method`(与 `default_mask` 维度相同)
`t`。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
def _合并掩码(
方法, t,
面具):
r将所有剪枝方法的掩码合并并返回一个新的掩码。
参数:
方法(BasePruningMethod 子类):剪枝方法
正在应用中。
t (torch.Tensor):表示剪枝参数的张量。
(与 mask 维度相同)。
mask (torch.Tensor):来自前一次剪枝迭代的掩码
返回:
new_mask (torch.Tensor): 新的掩码(torch.Tensor):结合旧掩码和当前剪枝方法的新掩码
of the old mask and the new mask from the current pruning method (of same dimensions as mask and t).
pruning method (of same dimensions as mask and t).
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
新口罩 =
遮罩
从现有掩码开始
新口罩 =
新口罩.
到(
数据类型=t.
数据类型)
# 计算 t 的一个切片,新剪枝方法将在其上操作
如果
方法.PRUNING_TYPE ==
无结构:
# 删除 t 中掩码为 1 的条目
slc = 遮罩 == 1
# 为结构剪枝,排除已完全剪枝的通道
# 完全剪枝
elif 方法.PRUNING_TYPE ==
结构化:
如果 not
有属性(
方法,
dim):
提升
属性错误(
"PRUNING_TYPE 的剪枝方法 "
'"structured" 需要定义属性 `dim`。'
)
# 通过移除已经归零的通道来找到要保留的通道
# (即 sum(entries) == 0 的位置)
n_dims = t.暗淡()
这是一个 2D 张量吗?3D 的吗?...
维度 =
方法.
维度
# 转换负索引
如果
维度 < 0:
维度 = n_dims +
维度
# 如果从 n_dims 中减去 dim 之后 dim 仍然为负
如果
维度 < 0:
提升
索引错误(
f索引超出张量的维度范围{n_dims}"
)
查找沿 dim = dim 维度尚未被完全过滤掉的频道
keep_channel = 面具.
总和(
暗淡=[d
为 d
在
范围(n_dims)
如果 d !=
暗淡]) != 0
# 创建切片以识别要剪枝的内容
slc = [切片(
无
] * n_dims
slc[暗淡] = keep_channel
elif 方法.PRUNING_TYPE ==
全局:
n_dims = 长度(t.shape)
这是一个 2D 张量吗?3D 的吗?...
slc = [切片(
无
] * n_dims
否则:
提升 ValueError(f
识别不到的 PRUNING_TYPE{
方法.PRUNING_TYPE}")
# 在张量 t 的非修剪切片上计算新的掩码
部分掩码 =
方法.
计算掩码(t[slc
]
默认掩码=
面具[slc])
新口罩[slc] =
部分口罩.
到(
数据类型=
新口罩.
数据类型)
返回
新口罩
方法 =
自身.
_剪枝方法[-1]
遮罩 =
_合并掩码(
方法, t,
默认掩码)
返回
面具
[文档]类 Identity(BasePruningMethod):
r"""这是一个不剪枝任何单元但使用全 1 掩码生成剪枝参数化的实用剪枝方法。"""
PRUNING_TYPE = "无结构"
def compute_mask(self, t, default_mask):
mask = default_mask
return mask
[文档] @类方法
def apply(cls, module, name):
r"""动态添加剪枝和张量的重新参数化。
添加前向预钩子,启用动态剪枝。
张量在原始张量意义上的重新参数化
以及修剪掩码。
Args:
要修剪的张量的模块(nn.Module)
name (str): 在 ``module`` 中用于剪枝的参数名称
将对其起作用。
"""
return super().apply(module, name)
[文档]
类
随机无结构(
基础剪枝方法):
r随机剪枝(当前未剪枝)张量中的单元。
参数:
name(字符串):在 ``module`` 中作为剪枝参数的参数名称
将起作用。
数量(整数或浮点数):要修剪的参数数量。
如果是浮点数,应在 0.0 和 1.0 之间,表示要修剪的参数比例。
如果是整数,表示要修剪的参数数量。
剪枝参数的绝对数量。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
PRUNING_TYPE = "无结构"
def 初始化(
自身,
金额):
检查剪枝量的有效性范围
_初始化剪枝数量验证(
金额)
自身.
数量 =
数量
def 计算掩码(
自身, t,
默认掩码):
检查修剪单元的数量是否不大于 t 参数的数量
# parameters in t
张量大小 = t.
元素个数()
# 计算要剪枝的单元数:如果为 int,则为数量
else 数量 * 张量大小
nparams_toprune = _compute_nparams_toprune(自身.
金额,
张量大小)
如果剪枝单元数量过大,则应引发错误
# 比 张量中的单元数多
_validate_pruning_amount
验证剪枝数量(nparams_toprune, 张量大小)
遮罩 =
默认掩码.
克隆(
内存格式=
火炬.
连续格式)
如果 nparams_toprune != 0:
# k=0 不支持 torch.kthvalue
概率 =
火炬.
随机类似(t)
topk = 火炬.topk(
概率.
视图(-1), k=nparams_toprune)
面具.
视图(-1
)topk.
索引] = 0
返回
遮罩
[文档] @类方法
def apply(cls, module, name, amount):
r"""动态添加剪枝和张量的重新参数化。
添加了前向预钩子,该钩子启用动态剪枝和
张量的重新参数化,以原始张量为基础
并且是修剪掩码。
Args:
模块(nn.Module):包含要修剪张量的模块
name(str):在 ``module`` 中 ``module`` 的参数名称,用于修剪
将执行。
数量(整数或浮点数):剪枝参数的数量。
如果是 ``float``,则应在 0.0 和 1.0 之间,并代表
如果是 ``int``,则代表
绝对剪枝参数数量。
```python
# 输入文本
input_text = '"""'
# 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 假设的翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
返回 super().apply(module, name, amount=amount)
[文档]
类
L1 非结构化(
基础剪枝方法):
r通过将具有最低 L1 范数的单元置零来剪枝(当前未剪枝)张量中的单元。
参数:
数量(整数或浮点数):要修剪的参数数量。
如果是浮点数,应在 0.0 和 1.0 之间,表示要修剪的参数比例。
如果是整数,表示要修剪的参数数量。
剪枝参数的绝对数量。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
PRUNING_TYPE = "无结构"
def 初始化(
自身,
金额):
检查剪枝量的有效性范围
_初始化剪枝数量验证(
金额)
自身.
数量 =
数量
def 计算掩码(
自身, t,
默认掩码):
检查修剪单元的数量是否不大于 t 参数的数量
# parameters in t
张量大小 = t.
元素个数()
# 计算要剪枝的单元数:如果为 int,则为数量
else 数量 * 张量大小
nparams_toprune = _compute_nparams_toprune(自身.
金额,
张量大小)
如果剪枝单元数量过大,则应引发错误
# 比 张量中的单元数多
_validate_pruning_amount
验证剪枝数量(nparams_toprune, 张量大小)
遮罩 =
默认掩码.
克隆(
内存格式=
火炬.
连续格式)
如果 nparams_toprune != 0:
# k=0 不支持 torch.kthvalue
# largest=True 表示取前 k 个;largest=False 表示取后 k 个
# 剪掉最小的 k 个
topk = 火炬.topk(
火炬.
绝对值(t).
视图(-1), k=nparams_toprune,
最大的=
错误)
# topk 将会有 .indices 和 .values
面具.
视图(-1
)topk.
索引] = 0
返回
遮罩
[文档] @classmethod
def apply(cls, module, name, amount, importance_scores=None):
r"""动态添加剪枝和张量的重新参数化。
添加了前向预钩子,使张量在动态剪枝和重新参数化方面成为可能,
重新参数化张量,以原始张量的形式进行。
并且是修剪掩码。
Args:
模块(nn.Module):包含要修剪张量的模块
name(str):在 ``module`` 中 ``module`` 的参数名称,用于修剪
将执行。
数量(整数或浮点数):剪枝参数的数量。
如果是 ``float``,则应在 0.0 和 1.0 之间,并代表
如果是 ``int``,则代表
绝对剪枝参数数量。
重要性得分(torch.Tensor):重要性得分张量(相同)
形状作为模块参数(用于计算剪枝掩码)。
这个张量中的值表示相应元素的重要性
参数中被剪枝的元素。
如果未指定或为空,将使用模块参数代替。
```python
# 输入文本
input_text = '"""'
# 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 假设的翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
返回 super().apply()
模块,名称,数量=amount,重要性得分=importance_scores
)
[文档]
类
随机结构化(
基础剪枝方法):
r随机修剪张量中的所有(目前未修剪的)通道。
参数:
数量(整数或浮点数):要修剪的参数数量。
如果是浮点数,应在 0.0 和 1.0 之间,表示要修剪的参数比例。
如果是整数,表示要修剪的参数数量。
剪枝参数的绝对数量。
dim(int,可选):定义剪枝通道的 dim 索引。默认:-1。
PRUNING_TYPE
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
PRUNING_TYPE = 结构化
def 初始化(
自身,
金额,
暗淡=-1):
检查数量有效范围
_初始化剪枝数量验证(
金额)
自身.
数量 =
数量
自身.
维度 =
维度
[文档] def
计算掩码(
自身, t,
默认掩码):
r计算并返回输入张量`t`的掩码。
从基础 ``default_mask``(它应该是一个全一的掩码)开始
如果张量尚未被剪枝),生成一个随机掩码
在 `default_mask` 上应用,通过随机置零通道
沿着张量指定的维度。
参数:
t (torch.Tensor):表示剪枝参数的张量。
default_mask (torch.Tensor):来自之前剪枝的基本掩码
在应用新掩码后需要遵守的迭代次数。
与`t`相同的维度。
返回:
掩码(torch.Tensor):应用于`t`的掩码,与`t`具有相同的维度。
抛出异常:
索引错误:如果`self.dim >= len(t.shape)`。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
检查张量是否有结构(即超过 1 维),
确保通道的概念是有意义的,
_validate_structured_pruning(t)
检查 self.dim 是否是索引 t 的有效维度,否则引发 IndexError 异常
_validate_pruning_dim(t, 自身.
暗淡)
# 检查剪枝通道的数量是否不大于 t 沿 dim 的通道数
# 剪枝维度上的通道数
张量大小 = t.shape[
自身.
暗淡]
# 计算要剪枝的单元数:如果为 int,则为数量
else 数量 * 张量大小
nparams_toprune = _compute_nparams_toprune(自身.
金额,
张量大小)
如果剪枝单元数量过大,则应引发错误
# 比 张量中的单元数多
_validate_pruning_amount
验证剪枝数量(nparams_toprune, 张量大小)
通过将其初始化为全 0 然后填充 topk.indices 指示的位置为 1s 来计算二进制掩码
# mask 具有与张量 t 相同的形状
# mask 具有与张量 t 相同的形状
def make_mask(t, 暗淡, nchannels, nchannels_toprune):
生成一个[0, 1]范围内的随机数以关联到每个通道
概率 =
火炬.
随机(nchannels)
# 为每个通道生成掩码,通过将分配了 k = nchannels_toprune 最低值的通道置零
# 获取分配了概率中 k = nchannels_toprune 最低值的通道
阈值 =
火炬.
第 k 大值(
概率, k=nchannels_toprune).values
通道掩码 =
概率 >
阈值
遮罩 =
火炬.
与...相同形状的零(t)
slc = [切片(
无
] *
长度(t.shape)
slc[暗淡] =
通道掩码
面具[slc] = 1
返回
遮罩
如果 nparams_toprune == 0:
# k=0 不支持 torch.kthvalue
遮罩 =
默认掩码
否则:
在先前的(可能为非结构化)掩码之上应用新的结构化掩码
# unstructured
遮罩 = make_mask(t,
自身.
暗淡,
张量大小, nparams_toprune)
遮罩 *=
默认掩码.
到(
数据类型=
面具.
数据类型)
返回
面具
[文档] @类方法
def apply(cls, module, name, amount, dim=-1):
r"""动态添加剪枝和张量的重新参数化。
添加前向预钩子,启用动态剪枝。
张量在原始张量意义上的重新参数化
以及修剪掩码。
Args:
要修剪的张量的模块(nn.Module)
name (str):在 ``module`` 中进行剪枝的参数名称
将会起作用。
amount (int 或 float):要剪枝的参数数量。
如果是 ``float`` 类型,应在 0.0 和 1.0 之间,并代表
参数剪枝的比例。如果为 ``int``,它表示
绝对剪枝参数数量。
dim (int, 可选): 沿着定义的维度索引
修剪通道。默认:-1。
"""
"""
返回 super().apply(module, name, amount=amount, dim=dim)
[文档]
类
结构化(
基础剪枝方法):
r基于张量中其 L\ ``n``-范数剪枝整个(当前未剪枝的)通道。
参数:
金额(整数或浮点数):要剪枝的通道数量。
如果是浮点数,应在 0.0 和 1.0 之间,表示要修剪的参数比例。
如果是整数,表示要修剪的参数数量。
剪枝参数的绝对数量。
n (int, float, inf, -inf, 'fro', 'nuc'): 请参阅关于 p 在 torch.norm 中有效参数的文档
entries for argument ``p`` in :func:`torch.norm`.
dim(int,可选):定义剪枝通道的 dim 索引。默认:-1。
PRUNING_TYPE
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
PRUNING_TYPE = 结构化
def 初始化(
自身,
金额, n,
暗淡=-1):
检查数量有效范围
_初始化剪枝数量验证(
金额)
自身.
数量 =
数量
自身.n = n
自身.
维度 =
维度
[文档] def
计算掩码(
自身, t,
默认掩码):
r计算并返回输入张量`t`的掩码。
从基础 ``default_mask``(它应该是一个全一的掩码)开始
如果张量尚未被剪枝),生成一个要应用的掩码
顶部将 `default_mask` 的通道置零
指定具有最低 L\ ``n``-范数的维度。
参数:
t (torch.Tensor):表示剪枝参数的张量。
default_mask (torch.Tensor):来自之前剪枝的基本掩码
在应用新掩码后需要遵守的迭代次数。
。与`t`具有相同的维度
返回:
掩码(torch.Tensor):应用于`t`的掩码,与`t`具有相同的维度。
抛出异常:
索引错误:如果`self.dim >= len(t.shape)`。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
检查张量是否有结构(即超过 1 维),
确保通道的概念是有意义的,
_validate_structured_pruning(t)
检查 self.dim 是否是索引 t 的有效维度,否则引发 IndexError 异常
_validate_pruning_dim(t, 自身.
暗淡)
# 检查剪枝通道的数量是否不大于 t 沿 dim 的通道数
# 剪枝维度上的通道数
张量大小 = t.shape[
自身.
暗淡]
# 计算要剪枝的单元数:如果为 int,则为数量
else 数量 * 张量大小
nparams_toprune = _compute_nparams_toprune(自身.
金额,
张量大小)
保留参数数量 =
张量大小 - nparams_toprune
如果剪枝单元数量过大,则应引发错误
# 比 张量中的单元数多
_validate_pruning_amount
验证剪枝数量(nparams_toprune, 张量大小)
# 结构化剪枝会剪除整个通道,因此我们需要知道
沿每个通道计算 L_n 范数,然后根据这个范数找到 topk
# 距离度量
标准 = _compute_norm(t,
自身.n,
自身.
暗淡)
# largest=True 表示取前 k 个;largest=False 表示取后 k 个
# 保持沿 dim=self.dim 的最大 k 通道
topk = 火炬.topk(
归一化, k=nparams_tokeep,
最大的=True)
# topk 将会有 .indices 和 .values
通过将其初始化为全 0 然后填充 topk.indices 指示的位置为 1s 来计算二进制掩码
# mask 具有与张量 t 相同的形状
# mask 具有与张量 t 相同的形状
def make_mask(t, 暗淡,
索引):
初始化掩码为 0
遮罩 =
火炬.
与...相同形状的零(t)
例如:slc = [None, None, None],如果 len(t.shape) = 3
slc = [切片(
无
] *
长度(t.shape)
将位置=dim 处的 None 替换为索引
# e.g.: slc = [None, None, [0, 2, 3]] 如果 dim=2 且 indices=[0,2,3]
slc[暗淡] =
索引
# 使用 slc 来切片掩码,并将所有条目替换为 1
# 例如:mask[:, :, [0, 2, 3]] = 1
面具[slc] = 1
返回
遮罩
如果 nparams_toprune == 0:
# k=0 不支持 torch.kthvalue
遮罩 =
默认掩码
否则:
遮罩 = make_mask(t,
自身.
暗淡, topk.
索引)
遮罩 *=
默认掩码.
到(
数据类型=
面具.
数据类型)
返回
面具
[文档] @类方法
def apply(cls, module, name, amount, n, dim, importance_scores=None):
r"""动态添加剪枝和张量的重新参数化。
添加了前向预钩子,以启用动态剪枝。
张量在原始张量意义上的重新参数化
以及修剪掩码。
Args:
要修剪的张量的模块(nn.Module)
name (str):在 ``module`` 中进行剪枝的参数名称
将会起作用。
amount (int 或 float):要剪枝的参数数量。
如果是 ``float`` 类型,应在 0.0 和 1.0 之间,并代表
参数剪枝的比例。如果为 ``int``,则表示要剪枝的参数数量。
要剪枝的参数的绝对数量。
n (int, float, inf, -inf, 'fro', 'nuc'):请参阅 :func:`torch.norm` 中参数 ``p`` 的有效条目文档。
n (int, float, inf, -inf, 'fro', 'nuc'):请参阅 :func:`torch.norm` 中参数 ``p`` 的有效条目文档。
dim (int): 沿着定义通道的维度索引
剪枝。
importance_scores (torch.Tensor): 用于计算剪枝掩码的重要性得分张量(与模块参数形状相同)
importance_scores (torch.Tensor): tensor of importance scores (of same
张量中的值表示正在剪枝的参数中相应元素的重要性。
如果未指定或为 None,将使用模块参数代替。
如果未指定或为 None,将使用模块参数代替。
"""
return super().apply(
模块,
名称,
amount=amount,
n=n,
dim=dim,
importance_scores=importance_scores,
)
[文档]class CustomFromMask(BasePruningMethod):
PRUNING_TYPE = "全局"
def __init__(self, mask):
self.mask = mask
def compute_mask(self, t, default_mask):
assert default_mask.shape == self.mask.shape
mask = default_mask * self.mask.to(dtype=default_mask.dtype)
return mask
[文档] @类方法
def apply(cls, module, name, mask):
r"""动态添加剪枝和张量的重新参数化。
添加前向预钩子,启用动态剪枝。
张量在原始张量意义上的重新参数化
以及修剪掩码。
Args:
要修剪的张量的模块(nn.Module)
name (str): 在 ``module`` 中用于剪枝的参数名称
将对其起作用。
"""
return super().apply(module, name, mask=mask)
[文档]def identity(module, name):
应用剪枝重参数化而不剪枝任何单元。
应用于对应张量的剪枝重新参数化
参数 ``name`` 在 ``module`` 中未实际剪枝
单元。就地修改模块(并返回修改后的模块)
by:
1) 添加一个名为 ``name+'_mask'`` 的命名缓冲区,对应于
由剪枝方法应用于参数 ``name`` 的二进制掩码。
2) 将参数 `name` 替换为其修剪版本,同时
原始(未修剪)参数存储在一个名为的新参数中
`name'_orig'.
注意:
面具是一个全为 1 的张量。
Args:
module (nn.Module): 包含要剪枝的张量的模块。
name (str): 在 ``module`` 中 ``module`` 的参数名称,用于剪枝
将执行。
返回:
模块 (nn.Module):输入模块的修改(即剪枝)版本
示例:
>>> # xdoctest: +SKIP
>>> m = prune.identity(nn.Linear(2, 3), 'bias')
>>> print(m.bias_mask)
tensor([1., 1., 1.])
"""
Identity.apply(模块, 名称)
返回模块
[文档]def 随机非结构化(module, 名称, 数量):
通过移除随机(当前未剪枝)的单元来剪枝张量。
剪枝与模块中名为 ``name`` 的参数对应的张量。
通过移除指定的 ``amount`` 个(当前未剪枝)单元。
随机选择。
在原模块上修改(并返回修改后的模块)的方式为:
1) 添加一个名为 ``name+'_mask'`` 的命名缓冲区,对应于通过剪枝方法应用于参数 ``name`` 的二进制掩码。
2) 将参数 ``name`` 替换为其剪枝版本,同时
2) 将参数 ``name`` 替换为其剪枝版本,同时
原始(未修剪)参数存储在名为的新参数中
``name+'_orig'``.
参数:
模块(nn.Module):包含要修剪张量的模块
name (str): 模块内参数名称,对其实施剪枝
将起作用。
数量 (int 或 float): 要剪枝的参数数量。
如果是 float 类型,应在 0.0 和 1.0 之间,并代表
参数剪枝的比例。如果为 ``int``,则表示剪枝的参数比例。
剪枝的参数绝对数量。
返回:
模块(nn.Module):修改后的(即剪枝的)输入模块版本
示例:
>>> # xdoctest: +SKIP
>>> m = prune.random_unstructured(nn.Linear(2, 3), 'weight', amount=1)
>>> torch.sum(m.weight_mask == 0)
tensor(1)
"""
RandomUnstructured.apply(module, name, amount)
返回 module
[文档]def l1_unstructured(module, name, amount, importance_scores=None):
r"""通过移除具有最低 L1 范数的单元来剪枝张量。
剪枝对应于在`module`中名为`name`的参数的张量
通过移除指定的`amount`个(当前未剪枝的)单元来实现
最低 L1 范数。
在原地进行模块修改(同时返回修改后的模块)
作者:
1) 添加一个名为 ``name+'_mask'`` 的命名缓冲区,对应于
通过剪枝方法应用于参数 `name` 的二进制掩码。
2) 用剪枝后的版本替换参数 `name`,而原始(未剪枝)参数存储在名为
`name'_orig` 的新参数中。
`name'_orig` 的新参数中。
Args:
模块 (nn.Module):包含要剪枝张量的模块
name (str):在 ``module`` 中将要进行剪枝的参数名称
将会作用。
参数剪枝的数量(整数或浮点数)。
如果是浮点数,应在 0.0 和 1.0 之间,表示要剪枝的参数比例。
如果是整数,表示要剪枝的参数的绝对数量。
表示要剪枝的参数的绝对数量。
importance_scores (torch.Tensor): 张量的重要性得分(与模块参数形状相同)
shape as module parameter) used to compute mask for pruning.
The values in this tensor indicate the importance of the corresponding
elements in the parameter being pruned.
如果未指定或为空,将使用模块参数代替。
返回:
模块(nn.Module):输入模块的修改版(即剪枝版)
示例:
>>> # xdoctest: +SKIP
>>> m = prune.l1_unstructured(nn.Linear(2, 3), 'weight', amount=0.2)
>>> m.state_dict().keys()
odict_keys(['bias', 'weight_orig', 'weight_mask'])
"""
L1Unstructured.apply(
模块,名称,amount=amount,importance_scores=importance_scores
)
返回模块
[文档]def 随机结构化(module, name, amount, dim):
r"""通过移除指定维度的随机通道来剪枝张量。
剪枝对应于在“module”中名为“name”的参数的张量
通过移除指定的(当前未修剪的)频道数量
沿着随机选择的指定 ``dim``
在原地修改模块(并返回修改后的模块)
通过:
1) 添加一个名为 ``name+'_mask'`` 的命名缓冲区,对应于通过剪枝方法应用于参数 ``name`` 的二进制掩码。
2) 将参数 ``name`` 替换为其剪枝版本,同时将原始(未剪枝)参数存储在名为的新参数中。
3) 替换参数 ``name`` 为其剪枝版本,而原始(未剪枝)参数则存储在名为的新参数中。
4) 替换参数 ``name`` 为其剪枝版本,而原始(未剪枝)参数则存储在名为的新参数中。
``name'_orig'``.
参数:
模块(nn.Module):包含要剪枝张量的模块
name(str):在 ``module`` 中要剪枝的参数名称
将执行。
数量(整数或浮点数):剪枝参数的数量。
如果是 ``float``,则应在 0.0 和 1.0 之间,并代表要剪枝的参数的
比例。如果是 ``int``,则代表要剪枝的参数的数量。
参数剪枝的绝对数量。
dim (int): 沿着定义剪枝通道的维度索引。
返回:
module (nn.Module): 修改后的(即剪枝的)输入模块版本。
示例:
>>> # xdoctest: +SKIP
>>> m = prune.random_structured(
... nn.Linear(5, 3), 'weight', amount=3, dim=1
... )
>>> columns_pruned = int(sum(torch.sum(m.weight, dim=0) == 0))
>>> print(columns_pruned)
3
"""
RandomStructured.apply(模块, 名称, 数量, 维度)
返回模块
[文档]def ln_structured(模块, 名称, 数量, n, 维度, 重要性分数=None):
通过移除指定维度上具有最低 L``n``-范数的通道来修剪张量。
修剪对应于`module`中名为`name`的参数的张量。
通过移除指定数量的(目前未修剪的)通道。
沿着具有最低 L``n``-范数的指定`dim`维度。
修改模块(并返回修改后的模块)
by:
1) 添加一个名为 ``name+'_mask'`` 的命名缓冲区,对应于
由剪枝方法应用于参数 ``name`` 的二进制掩码。
2) 将参数 `name` 替换为其修剪版本,同时
原始(未修剪)参数存储在一个名为的新参数中
`name'_orig'.
参数:
(nn.Module): 包含要剪枝张量的模块
name (str): 在 ``module`` 中用于剪枝的参数名称
将要起作用的。
amount (int or float): 要剪枝的参数数量。
如果为浮点数,应在 0.0 和 1.0 之间,表示
参数剪枝的比例。如果为 ``int``,它表示
绝对剪枝参数数量。
n (int, float, inf, -inf, 'fro', 'nuc'):请参阅有效值的文档
entries for argument ``p`` in :func:`torch.norm`.
dim (int): 沿着该维度定义通道进行剪枝的索引。
importance_scores (torch.Tensor): 与模块参数形状相同的 importance_scores 张量(用于计算剪枝掩码)。
importance_scores (torch.Tensor): tensor of importance scores (of same shape as module parameter) used to compute mask for pruning.
张量中的值表示正在剪枝的参数中相应元素的重要性。
如果未指定或为 None,将使用模块参数代替。
如果未指定或为 None,将使用模块参数代替。
返回值:
模块(nn.Module):输入模块的修改版(即剪枝版)
示例:
>>> 从 torch.nn.utils 导入 prune
>>> m = prune.ln_structured(
nn.Conv2d(5, 3, 2), '权重', 数量=0.3, 维度=1, n=负无穷
... )
"""
LnStructured.apply(
模块,名称,数量,n,维度,重要性得分=importance_scores
)
返回模块
[文档]def
全球非结构化(
参数, pruning_method,
重要性得分=
无, **kwargs):
r""
通过应用指定的 `剪枝方法`,全局剪枝对应于 `parameters` 中所有参数的张量。
在原地修改模块,通过:
1) 添加一个名为 ``name+'_mask'`` 的命名缓冲区,对应于
通过剪枝方法应用于参数 ``name`` 的二进制掩码。
2) 将参数 ``name`` 替换为其剪枝版本,同时
原始(未修剪)参数存储在一个新的参数中,名为
``name+'_orig'``。
参数:
参数((模块,名称)元组的可迭代对象):全局修剪模型的参数,即通过聚合所有
参数((模块,名称)元组的可迭代对象):全局修剪模型的参数,即通过聚合所有
在决定要剪枝的权重之前。模块必须是
类型:`nn.Module` 类,名称必须是一个字符串。
剪枝方法(函数):此模块中的一个有效剪枝函数
或用户实现的自定义一个满足
实施指南,并具有 `PRUNING_TYPE='unstructured'`。
importance_scores(字典):将(模块,名称)元组映射到
对应参数的重要性得分张量。该张量
应与参数具有相同的形状,并用于计算
剪枝的掩码。
如果未指定或为空,则将使用该参数
的重要性分数。
kwargs:其他关键字参数,例如:
量(int 或 float):要剪枝的参数数量
指定参数。
如果是浮点数,应在 0.0 和 1.0 之间,表示要修剪的参数比例。
如果是整数,表示要修剪的参数数量。
剪枝参数的绝对数量。
抛出异常:
TypeError: 如果 ``PRUNING_TYPE != 'unstructured'``
注意:
由于全局结构化剪枝在参数大小未按大小归一化时没有太多意义,因此我们现在将全局剪枝的范围限制为非结构化方法。
我们现在将全局剪枝的范围限制为非结构化方法,因为全局结构化剪枝在参数大小未按大小归一化时没有太多意义。
我们现在将全局剪枝的范围限制为非结构化方法。
示例:
>>> from torch.nn.utils import prune
>>> 从 collections 导入 OrderedDict
>>> net = nn.Sequential(OrderedDict([
... ('first', nn.Linear(10, 4)),
... ('second', nn.Linear(4, 1)),
... ]))
>>> parameters_to_prune = (
... (net.first, 'weight'),
... (net.second, 'weight'),
... )
>>> prune.global_unstructured(
... 参数剪枝,
... 剪枝方法=prune.L1Unstructured,
... 数量=10,
... )
>>> 打印(sum(torch.nn.utils.parameters_to_vector(net.buffers()) == 0))
tensor(10)
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
# 确保参数是一个元组列表或生成器
如果 not isinstance(
参数,
迭代器):
提升
类型错误(
"global_unstructured(): 参数不是一个可迭代对象")
重要性得分 =
重要性得分
如果
重要性得分
是 not None
否则 {}
如果 not isinstance(
重要性得分,
字典):
提升
类型错误(
global_unstructured()函数中,importance_scores 必须为 dict 类型)
将重要性分数扁平化以考虑全局剪枝
相关的重要性分数 =
火炬.nn.
工具.
参数向量化(
[
重要性得分.
获取((
模块,
名称), getattr(
模块,
名称))
为 (
模块,
名称)
在
参数
]
)
# 同样,如果存在,则展平掩码,或使用展平的向量
# 与 t 相同维度的 1 的数量
默认掩码 =
火炬.nn.
工具.
参数向量化(
[
getattr(模块,
名称 +
_mask,
火炬.
喜欢的(getattr(
模块,
名称)))
为 (
模块,
名称)
在
参数
]
)
使用规范剪枝方法计算新掩码,即使该
# 参数现在是`parameters`的一个扁平化版本
容器 = PruningContainer()
容器._tensor_name =
"临时"
# 使其与 `方法` 相匹配
方法 = pruning_method(**kwargs)
方法._tensor_name =
"临时"
# 使其与 `container` 的格式相匹配
如果
方法.PRUNING_TYPE !=
无结构:
提升
类型错误(
'仅支持 "非结构化" PRUNING_TYPE 用于 '
f"的 `pruning_method`。找到的方法 "{pruning_method}
的类型{
方法.PRUNING_TYPE}"
)
容器.
添加剪枝方法(
方法)
# 使用 `PruningContainer` 的 `compute_mask` 方法来组合
# 新方法计算出的掩码与现有的掩码
最终掩码 =
容器.
计算掩码(
相关重要性得分,
默认掩码)
# 用于切割掩码以匹配每个参数形状的指针
指针 = 0
为
模块,
名称
在
参数:
参数 = getattr(
模块,
名称)
# 参数的长度
num 参数 =
参数.
元素数量()
切片掩码,重塑它
参数掩码 =
最终掩码[
指针 :
指针 + num_param].
以查看方式(
参数)
# 将正确的预计算掩码分配给每个参数,并添加到
# forward_pre_hooks 中,就像任何其他剪枝方法一样
custom_from_mask(模块,
名称,
面具=param_mask)
# 将指针递增以继续切片 final_mask
指针 += num_param
[文档]def custom_from_mask(module, name, mask):
通过应用在 ``mask`` 中预计算的掩码来修剪 ``module`` 中名为 ``name`` 的参数对应的张量。
就地修改模块(并返回修改后的模块)的方式:
1) 添加一个名为 ``name+'_mask'`` 的命名缓冲区,对应于通过修剪方法应用于参数 ``name`` 的二进制掩码。
4) 对参数 ``name`` 应用修剪方法得到的二进制掩码。
2) 将参数 `name` 替换为其修剪版本,同时
原始(未修剪)参数存储在一个名为的新参数中
`name'_orig'.
参数:
(nn.Module):包含要剪枝张量的模块
name (str):在 ``module`` 中参数的名称,剪枝将作用于其上
将要起作用。
mask (Tensor):应用于参数的二进制掩码。
返回值:
module (nn.Module):输入模块的修改(即剪枝)版本
示例:
>>> 从 torch.nn.utils 导入 prune
>>> m = prune.custom_from_mask(
... nn.Linear(5, 3), name='bias', mask=torch.tensor([0, 1, 0]))
... )
>>> print(m.bias_mask)
tensor([0., 1., 0.])
"""
CustomFromMask.apply(module, name, mask)
返回 module
[文档]def remove(module, name):
从模块中移除剪枝重参数化以及前向钩子中的剪枝方法。
修剪的参数名为“name”将永久保留修剪状态,该参数
命名参数 `name'_orig'' 已从参数列表中删除。同样地,
缓冲区 "name'_mask'" 已从缓冲区中移除。
注意:
剪枝操作本身不会被撤销或反转!
参数:
模块(nn.Module):包含要剪枝张量的模块
name(str):在 ``module`` 中要剪枝的参数名称
将起作用。
示例:
>>> m = random_unstructured(nn.Linear(5, 7), name='weight', amount=0.2)
>>> m = remove(m, name='weight')
"""
for k, hook in module._forward_pre_hooks.items():
如果 isinstance(hook, BasePruningMethod) 且 hook._tensor_name 等于 name:
hook.remove(module)
del module._forward_pre_hooks[k]
返回 module
raise ValueError(
f"参数'{name}'的模块{module}必须在移除修剪之前进行修剪"
)
[文档]def is_pruned(module):
检查模块是否被剪枝,可以通过查找剪枝预钩子来实现。
检查 `module` 是否被剪枝,可以通过查找
其模块中的 `forward_pre_hooks`,这些模块继承自
class:`BasePruningMethod`。
Args:
模块(nn.Module):一个已剪枝或未剪枝的对象
Returns:
是否对 ``module`` 进行剪枝的二进制答案。
示例:
>>> 从 torch.nn.utils 导入 prune
>>> m = nn.Linear(5, 7)
>>> print(prune.is_pruned(m))
False
>>> prune.random_unstructured(m, name='weight', amount=0.2)
>>> print(prune.is_pruned(m))
True
"""
for _, submodule in module.named_modules():
for hook in submodule._forward_pre_hooks.values():
if isinstance(hook, BasePruningMethod):
返回 True
返回 False
def _初始化剪枝数量验证(
金额):
r初始化时验证金额范围的辅助函数。
参数:
数量(整数或浮点数):要修剪的参数数量。
如果是浮点数,应在 0.0 到 1.0 之间,表示要剪枝参数的比例。
如果是整数,表示要剪枝的参数数量。
剪枝参数的绝对数量。
抛出异常:
ValueError:如果 amount 是一个不在[0, 1]范围内的浮点数,或者是一个负数。
整数。
TypeError:如果 amount 既不是浮点数也不是整数。
注意:
这并没有考虑到要剪枝的张量参数数量,
该参数在剪枝时才知晓。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
如果 not isinstance(
金额,
数字.
实数):
提升
类型错误(f
"金额类型无效:"{
金额}
。必须是整数或浮点数。")
如果 (isinstance(
金额,
数字.
积分)
和
数量 < 0)
或 (
not isinstance(金额,
数字.
积分)
# 所以它是一个浮点数
和 (float(
金额) > 1.0
或 float(
金额) < 0.0)
):
提升 ValueError(
f"数量="{
金额}
应该是一个在[0, 1]范围内的浮点数或非负整数
)
def
_validate_pruning_amount
验证剪枝数量(金额,
张量大小):
r验证剪枝量相对于数据规模是否合理。
验证辅助器,用于检查剪枝参数的数量。
剪枝量(整数或浮点数):要剪枝的参数数量。相对于数据规模(`tensor_size`)是否合理。
参数:
数量(整数或浮点数):要修剪的参数数量。
如果是浮点数,应在 0.0 到 1.0 之间,表示要剪枝参数的比例。
如果是整数,表示要剪枝的参数数量。
剪枝参数的绝对数量。
tensor_size(整数):要剪枝的 tensor 中的参数的绝对数量
剪枝。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
# TODO: 考虑移除此检查,允许用户指定
# 要剪枝的单元数量大于要剪枝的单元数量
# 在这种情况下,张量将被完全剪枝。
如果 isinstance(
金额,
数字.
积分)
和
数量 >
张量大小:
提升 ValueError(
f"数量="{
金额}
应小于修剪参数的数量={
张量大小}"
)
def _validate_structured_pruning(t):
r验证要剪枝的张量至少是二维的。
验证辅助器,用于检查要剪枝的张量是多维的,
以确保“通道”这一概念有明确的定义。
参数:
t (torch.Tensor):表示剪枝参数的张量。
抛出异常:
ValueError:如果张量`t`不是至少 2 维的。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
形状 = t.
形状
如果
长度(shape)
≤ 1:
提升 ValueError(
"结构化剪枝只能应用于"
"多维张量。找到形状为"
f"{shape}的{
长度(shape)}
的维度
)
def _compute_nparams_toprune(金额,
张量大小):
r将修剪数量从百分比转换为绝对值。
由于数量可以表示为绝对值或
张量中单元/通道数量的百分比,此实用程序
函数将百分比转换为绝对值以进行标准化
处理剪枝的方式。
参数:
数量(整数或浮点数):要修剪的参数数量。
如果是浮点数,应在 0.0 到 1.0 之间,表示要剪枝参数的比例。
如果是整数,表示要剪枝的参数数量。
剪枝参数的绝对数量。
tensor_size(整数):要剪枝的 tensor 中的参数的绝对数量
剪枝。
返回:
int:张量中要剪枝的单元数
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
已经在_init_pruning_amount_pruning 中检查了类型
如果 isinstance(
金额,
数字.
积分):
返回
数量
否则:
返回
四舍五入(
数量 *
张量大小)
def _validate_pruning_dim(t, 暗淡):
r验证剪枝维度是否在张量维度的范围内。
参数:
t (torch.Tensor):表示剪枝参数的张量。
dim (int):定义剪枝通道的维度索引
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
如果
维度 >= t.
暗淡():
提升
索引错误(f
无效索引{
暗淡}
对于大小为的张量{t.shape}")
def _compute_norm(t, n, 暗淡):
r计算张量在所有维度上(除了指定的维度)的 L_n-范数。
L_n-范数将在张量`t`的所有条目上计算,除了由 dim 指定的维度。
除了由 dim 指定的维度之外的所有维度。
举例:如果`t`的形状为 3x2x4,且 dim=2(最后一个维度),那么范数将有大小[4],每个条目将代表使用每个 4 个通道的 3x2=6 个条目计算出的`L_n`-范数。
那么“范数”将有大小[4],每个条目将代表使用每个 4 个通道的 3x2=6 个条目计算出的`L_n`-范数。
`L_n`-范数将使用每个 4 个通道的 3x2=6 个条目进行计算。
参数:
t (torch.Tensor):表示剪枝参数的张量。
n (int, float, inf, -inf, 'fro', 'nuc'): 请参阅关于 p 在 torch.norm 中有效参数的文档
参数 entries 的有效条目
dim (int): 识别要剪枝的通道的维度
返回:
norm (torch.Tensor): 在所有维度上计算 L_n 范数,除了
对于 `dim`。根据构造,`norm.shape = t.shape[-1]`。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
# 维度 = 所有轴,除了由 `dim` 指定的那个
dims = 列表(
范围(t.
暗淡()))
# 转换负索引
如果
维度 < 0:
维度 =
维数[
暗淡]
维数.
删除(
暗淡)
标准 =
火炬.
归一化(t, p=n,
暗淡=
维数)
返回
标准