• 文档 >
  • 模块代码 >
  • torch >
  • torch.nn.utils.prune
快捷键

torch.nn.utils.prune 源代码

# 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, 暗淡=维数) 返回 标准

© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源,获取您的疑问解答

查看资源