# mypy: 允许未类型化定义
来自
枚举
导入
自动,
枚举
来自
打字
导入
可选
导入
火炬
导入 torch.nn.functional
作为 F
来自
火炬
导入
张量
来自 torch.nn.modules
导入
模块
来自 torch.nn.utils
导入
参数化
__all__ = [正交,
谱范数,
权重范数]
def _is_orthogonal(Q, eps=无):
n, k = Q.尺寸(-2), Q.
尺寸(-1)
Id = 火炬.
眼睛(k,
数据类型=Q.
数据类型,
设备=Q.
设备)
一个合理的 eps,但不要太大
eps = 10.0 * n * 火炬.finfo(Q.
数据类型).eps
返回
火炬.allclose(Q.mH @ Q, Id,
精度=eps)
def _正交化_(A):
假设 A 是一个高矩阵。
计算 Q 因子,使得 A = QR(A 可能是复数),并且 diag(R)是实数且非负。
"源代码"
X, 塔乌 =
火炬.geqrf(A)
Q = 火炬.
线性代数.
ouseholder 乘积(X,
淘)
X 的对角线是 R 的对角线(R 总是实数),所以我们通过其符号进行归一化
Q *= X.对角线(dim1=-2, dim2=-1).sgn().
展平(-2)
返回 Q
类 _OrthMaps(
枚举):
矩阵指数 =
自动()
凯莱 =
自动()
ouseholder =
自动()
类
_正交(
模块):
基础:
张量
def 初始化(
self, 重量,
正交映射: _OrthMaps, *,
使用平凡化=
真实
) -> 无:
超级().
初始化()
# 房屋持有者复数
# 对于复数张量,无法从反射器计算必要的张量 `tau`。
# linalg.householder_product。
# 要看到这一点,请注意反射器的形状如下:
# 0 0 0
# * 0 0
# * * 0
# 对于复矩阵,给出 n(n-1) 个(实)参数。现在,你需要 n^2 个参数
将单元矩阵参数化。单独保存 tau 也不行,因为
并非每个 `(A, tau)` 的组合都给出一个幺正矩阵,这意味着如果我们优化
将它们作为独立的张量时,我们不会保持约束
等价的推理也适用于矩形矩阵
如果
重量.
是复杂的()
和
正交映射 == _OrthMaps.
房屋持有者:
提升 ValueError(
"房屋持有者参数化不支持复数张量。"
)
self.形状 =
重量.
形状
self.正交映射 =
正交映射
如果
使用平凡化:
self.注册缓冲区(
基础,
无)
def 前向(self, X:
火炬.
张量) ->
火炬.
张量:
n, k = X.尺寸(-2), X.
尺寸(-1)
交换 = n < k
如果
交换:
X = X.mT
n, k = k, n
# 这里 n > k 且 X 是一个高矩阵
如果 (
self.正交映射 == _OrthMaps.
矩阵指数
或 self.
正交映射 ==
_正交映射.
凯莱
):
我们只需要 n x k - k(k-1)/2 个参数
X = X.三角()
如果 n != k:
嵌入到一个正方形矩阵中
X = 火炬.
猫(
[X, X.新零(n, n - k).
展开(*X.shape
[-2
] -1, -1
)],
暗淡=-1
)
A = X - X.mH
A 是斜对称的(或斜厄米对称的)
如果 self.
正交映射 == _OrthMaps.
矩阵指数:
Q = 火炬.
矩阵指数(A)
elif self.正交映射 == _OrthMaps.
凯莱:
# 计算凯莱收缩 (I+A/2)(I-A/2)^{-1}
Id = 火炬.
眼睛(n,
数据类型=A.
数据类型,
设备=A.
设备)
Q = 火炬.
线性代数.
求解(
火炬.
添加(Id, A,
阿尔法=-0.5),
火炬.
添加(Id, A,
阿尔法=0.5)
)
# Q 现在是正交(或幺正)的,大小为(..., n, n)
如果 n != k:
Q = Q[..., :k]
# Q 的大小是 X(尽管可能是转置的)
否则:
# X 是实数,因为我们不支持复数形式的豪斯霍尔德变换
A = X.三角(
对角线=-1)
塔乌 = 2.0 / (1.0 + (A * A).
总和(
暗淡=-2))
Q = 火炬.
线性代数.
ouseholder 乘积(A,
淘)
# X 的对角线是 1 和 -1
因此我们不想通过这个来区分或者更新 X 的对角线,所以进行了类型转换
Q = Q * X.对角线(dim1=-2, dim2=-1).int().
展平(-2)
如果
有属性(self,
基础):
Q = self.基础 @ Q
如果
交换:
Q = Q.mT
返回 Q # type: ignore[possibly-undefined]
@torch.自动微分.
不梯度()
def 右逆(self, Q:
火炬.
张量) ->
火炬.
张量:
如果 Q.
形状 != self.shape:
提升 ValueError(
f预期是一个矩阵或矩阵批次的形状{self.shape}
.
f"获得了一个形状的张量"{Q.shape}
。
)
Q 初始化 = Q
n, k = Q.尺寸(-2), Q.
尺寸(-1)
转置 = n < k
如果
转置:
Q = Q.mT
n, k = k, n
# 我们始终确保在每条路径上都要复制 Q
如果 not
有属性(self,
"基础"):
# 右逆 [右逆 expm cayley]
# 如果我们不使用 use_trivialization=True,我们只需实现前向的逆
# 映射对于豪斯霍尔德映射。为了理解这一点,考虑 Cayley 映射,
我们需要找到一个矩阵 \(X \in \mathbb{R}^{n \times k}\),使得:
\(Y = \text{torch.cat}([X.tril(), X.new_zeros(n, n - k).expand(*X.shape[:-2], -1, -1)], dim=-1)\)
\(A = Y - Y.mH\)
\(cayley(A)[:, :k]\)
不清楚如何给出原始张量。
或许通过类似于 QR 的代数操作?
爱德曼、阿里亚斯和史密斯中的推论 2.2?
如果 (
self.正交映射 ==
正交映射.
凯莱
或 self.
正交映射 ==
正交映射.
矩阵指数
):
提升
不支持的操作异常(
"无法将矩阵指数赋值 "
"或凯莱参数化赋值,当 use_trivialization=False 时。"
)
# 如果参数化等于 _OrthMaps.householder,则通过 QR 分解使 Q 正交。
# 这里 Q 总是真实的,因为我们不支持 householder 和复矩阵。
# 见注解[Householder 复数]
A, 塔乌 =
火炬.geqrf(Q)
# 我们希望有一个分解 X = QR,使得 diag(R) > 0,否则我们可以
# 将正交矩阵 Q 分解为 Q = (-Q)@(-Id),这是一个有效的 QR 分解
Q 的对角线是 R 的 qr 分解的对角线
A.对角线(dim1=-2, dim2=-1).sign_()
# 等于零是可以的,因为 LAPACK 在不希望时返回精确的零
# 不使用特定的反射
A.对角线(dim1=-2, dim2=-1
)
塔乌 == 0.0] *= -1
返回 A.mT
如果 transpose
否则 A
否则:
如果 n == k:
我们检查 Q 是否正交
如果 not _is_orthogonal(Q):
Q = _make_orthogonal(Q)
否则:
# 是正交的
Q = Q.克隆()
否则:
# 完成将一个 Q 矩阵转换为一个 n x n 正交矩阵
N = 火炬.randn(
*(Q.尺寸()[:-2] + (n, n - k)),
数据类型=Q.
数据类型,
设备=Q.
设备
)
Q = 火炬.
猫([Q, N
]
暗淡=-1)
Q = _make_orthogonal(Q)
self.基础 = Q
# 返回 -Id 是必要的,因为我们使用对角线
# 使用 Householder 参数化。使用 -Id 使得:
householder(torch.zeros(m,n)) == torch.eye(m,n)
普通版本的 eye_like
neg_Id = 火炬.
与...相同形状的零(Q_init)
否定 ID.
对角线(dim1=-2, dim2=-1).
填充_(-1.0)
返回
负标识符
[文档]def
正交的(
模块:
模块,
名称:
字符串 =
权重,
正交映射:
可选[
字符串] =
无,
*,
使用平凡化:
布尔类型 = True,
) -> 模块:
r将正交或单位矩阵参数化应用于矩阵或矩阵批。
设 :math:`\mathbb{K}` 为 :math:`\mathbb{R}` 或 :math:`\mathbb{C}`
参数化的矩阵 :math:`Q \in \mathbb{K}^{m \times n}` 是 **正交** 的
.. math::
\begin{align*}
\( Q^{\text{H}}Q = \mathrm{I}_n \) (如果 \( m \geq n \))
QQ^{\text{H}} = \mathrm{I}_m \text{(如果 } m < n \text{)}
\end{align*}
当 \( Q \) 是复数时,\( Q^{\text{H}} \) 是共轭转置
当 \( Q \) 是实值时,其转置
\( \mathrm{I}_n \) 是 \( n \) 维单位矩阵。
简单来说,当 \( m \geq n \) 时,\( Q \) 将具有正交归一列。
否则,具有正交归一行。
如果张量具有超过两个维度,我们将其视为形状为`(..., m, n)`的矩阵批次。
矩阵 :math:`Q` 可以通过三种不同的 `orthogonal_map` 在原始张量的基础上进行参数化:
- ``"matrix_exp"``/``"cayley"``:
the :func:`~torch.matrix_exp` :math:`Q = \exp(A)` and the `Cayley map`_
math:`Q = (\mathrm{I}_n + A/2)(\mathrm{I}_n - A/2)^{-1}` are applied to a skew-symmetric
math:`A` to give an orthogonal matrix.
- ``"householder"``: 使用 Householder 反射器计算乘积
(:func:`~torch.linalg.householder_product`).
``"matrix_exp"``/``"cayley"`` 通常比 ``"householder"`` 更快地使参数化权重收敛,但它们在计算非常瘦或非常宽的矩阵时速度较慢。
``"householder"``, 但它们在计算非常瘦或非常宽的矩阵时速度较慢。
如果 `use_trivialization=True`(默认),参数化实现了“动态平凡化框架”
额外矩阵 :math:`B \in \mathbb{K}^{n \times n}` 存储于
`module.parametrizations.weight[0].base`。这有助于
参数化层的收敛以牺牲一些额外内存使用为代价。
查看《流形上基于梯度的优化的平凡化》_。
math:`Q` 的初始值:
如果原始张量未参数化且`use_trivialization=True`(默认),初始值
原张量 \( Q \) 的特征值是正交的(或在复数情况下是酉的)
并且它通过 QR 分解进行正交化(参见:func:torch.linalg.qr)。
同样,当未参数化且 `orthogonal_map="householder"` 时,即使 `use_trivialization=False`,也会发生这种情况。
否则,初始值是所有已注册的组成结果
应用于原始张量的参数化。
.. 注意::
此函数使用参数化功能实现
在::func:`~torch.nn.utils.parametrize.register_parametrization`。
.. _`凯莱映射`: https://zh.wikipedia.org/wiki/凯莱变换#矩阵映射
.. _`流形上基于梯度的优化的平凡化`: https://arxiv.org/abs/1909.09501
Args:
模块 (nn.Module):注册参数化的模块。
名称 (str, 可选):要正交化的张量的名称。默认值:`"weight"`。
orthogonal_map (str, 可选): 以下之一:``"matrix_exp"``, ``"cayley"``, ``"householder"``。
默认:如果矩阵是方阵或复数,则为 ``"matrix_exp"``, 否则为 ``"householder"``。
use_trivialization (bool, 可选): 是否使用动态平凡化框架。
默认:``True``。
返回:
将具有正交参数化的原始模块注册到指定的
重量
示例::
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_LAPACK)
>>> orth_linear = 正交线性层(nn.Linear(20, 40))
>>> orth_linear
ParametrizedLinear(
in_features=20, out_features=40, bias=True
(parametrizations): ModuleDict(
(weight): ParametrizationList(
(0): _正交()
)
)
)
>>> # xdoctest: +IGNORE_WANT
>>> Q = orth_linear.weight
>>> torch.dist(Q.T @ Q, torch.eye(20))
tensor(4.9332e-07)
"源代码"
权重 = getattr(
模块,
名称,
无)
如果 not isinstance(
重量,
张量):
提升 ValueError(
f模块{
模块}
'没有名为'的参数或缓冲区{
名称}
)
我们可以将其实现为 1 维张量的球面映射
但我认为这会让更多的人受害而不是受益
如果
重量.
维数 < 2:
提升 ValueError(
预期得到一个矩阵或矩阵批
f获得一个张量{
重量.ndim}
尺寸."
)
如果
正交映射
是
无:
正交映射 = (
矩阵指数
如果
重量.
尺寸(-2) ==
重量.
尺寸(-1)
或
重量.
是复杂的()
否则
户主
)
正交枚举 = getattr(
_正交映射,
正交映射,
无)
如果 orth_enum
是
无:
提升 ValueError(
'正交映射必须是 "matrix_exp"、"cayley" 或 "householder" 之一。'
f"获取:"{orthogonal_map}"
)
orth = 正交(
重量,
正交枚举,
使用平凡化=
使用平凡化)
参数化.
注册参数化(
模块,
名称,
正交,
不安全=True)
返回
模块
类
_权重归一化(
模块):
def 初始化(
self,
暗淡:
可选[int] = 0,
) -> 无:
超级().
初始化()
如果
维度
是
无:
维度 = -1
self.维度 =
维度
def 前向(self,
重量_g,
重量_v):
返回
火炬.
_权重归一化(
重量_v,
重量_g, self.
暗淡)
def 右逆矩阵(self,
重量):
重量_g =
火炬.
除维度外的范数(
重量, 2, self.
暗淡)
重量_v =
权重
返回
重量_g,
重量_v
[文档]def
重量归一化(
模块:
模块,
名称:
字符串 =
权重,
暗淡:
整型 = 0):
r将权重归一化应用于给定模块中的参数。
.. math::
\mathbf{w} = g \dfrac{\mathbf{v}}{\|\mathbf{v}\|}
权重归一化是一种重新参数化方法,将权重张量的幅度与其方向解耦。这取代了指定的参数。
权重张量的幅度与其方向解耦。这取代了指定的参数。
通过:attr:`name`使用两个参数:一个指定大小,另一个指定方向。
默认情况下,使用`dim=0`时,范数是独立于每个输出通道/平面的计算的。
要计算整个权重张量的范数,请使用。
要计算整个权重张量的范数,请使用。
`dim=None`
查看 https://arxiv.org/abs/1602.07868
Args:
模块(Module):包含模块
名称(str,可选):权重参数的名称
dim(int,可选):计算范数的维度
返回:
带权重范数钩子的原始模块
示例::
>>> m = weight_norm(nn.Linear(20, 40), name='weight')
>>> m
ParametrizedLinear(
in_features=20, out_features=40, bias=True
(parametrizations): ModuleDict(
(weight): ParametrizationList(
(0): _WeightNorm()
)
)
)
>>> m.parametrizations.weight.original0.size()
torch.Size([40, 1])
>>> m.parametrizations.weight.original1.size()
torch.Size([40, 20])
"源代码"
_权重归一化 =
权重归一化(
暗淡)
参数化.
注册参数化(
模块,
名称,
_权重归一化,
不安全=True)
def _权重归一化兼容钩子(
state_dict,
前缀,
本地元数据,
严格的,
缺少键,
预期之外的键,
错误信息,
):
g 键 = f"{
前缀}{
名称}_g"
v 键 = f"{
前缀}{
名称}_v"
如果
g 键
在
状态字典
和
v 键
在 state_dict:
原始 0 = state_dict.
弹出(
g 键)
原始文本 1 = state_dict.
弹出(
v_键)
state_dict[f"{前缀}
参数化。{
名称}
.原始 0] =
原始 0
state_dict[f"{前缀}
参数化{
名称}
.原始 1] =
原始 1
模块._register_load_state_dict_pre_hook(
_权重归一兼容钩子)
返回
模块
类
_频谱归一(
模块):
def 初始化(
self,
重量:
火炬.
张量,
n 次幂迭代次数:
整型 = 1,
暗淡:
整型 = 0,
eps: 浮点数 = 1e-12,
) -> 无:
超级().
初始化()
维数 =
重量.
维数
如果
维度 >=
维数
或
维度 < -ndim:
提升
索引错误(
"维度超出范围(预期应在范围内“)
f
"[
"{ndim}, {维数 - 1}
]但得到{
暗淡})"
)
如果 n_power_iterations
≤ 0:
提升 ValueError(
预期 n_power_iterations 为正数,但
f获取 n_power_iterations={n_power_iterations}"
)
self.维度 =
维度
如果
维度 >= 0
否则
维度 +
维数
self.eps = eps
如果
维数 > 1:
对于 ndim == 1,我们不需要进行近似(参见 _SpectralNorm.forward)
self.n_power_iterations = n_power_iterations
weight_mat = self.重塑权重为矩阵(
重量)
h, w = 权重矩阵.
尺寸()
u = 权重矩阵.
新空(h).
正常的(0, 1)
v = 权重矩阵.
新空(w).
正常的(0, 1)
self.注册缓冲区("_u", F.normalize(u,
暗淡=0, eps=self.eps))
self.注册缓冲区("_v", F.normalize(v,
暗淡=0, eps=self.eps))
从 u, v 初始化为一些合理的值开始,通过执行幂方法迭代
幂方法的迭代次数
self._幂方法(
权重矩阵, 15)
def 将权重重塑为矩阵(self,
重量:
火炬.
张量) ->
火炬.
张量:
# 预设条件
断言
重量.
维数 > 1
如果 self.
维度 != 0:
# 将维度排列到前面
权重 =
重量.
排列(
self.暗淡, *(d
为 d
在
范围(
重量.
暗淡())
如果 d != self.
暗淡)
)
返回
重量.
展平(1)
@torch.自动微分.
不梯度()
def 功率法(self,
权重矩阵:
火炬.
张量,
n 次幂迭代: int) ->
无:
# 请参阅 torch/nn/utils/spectral_norm.py 中的原始注释
# NB: 如果设置 `do_power_iteration`,则 `u` 和 `v` 向量将在 **原地** 更新。这非常重要
# 因为在 `DataParallel` 前向传播中,向量(作为缓冲区)是从并行化模块广播到每个模块副本的
# 因为在 `DataParallel` 前向传播中,向量(作为缓冲区)是从并行化模块广播到每个模块副本的
# 因为在 `DataParallel` 前向传播中,向量(作为缓冲区)是从并行化模块广播到每个模块副本的
# 这是一个动态创建的新模块对象。每个副本
# 都运行自己的谱范数幂迭代。所以简单地将
# 更新后的向量分配给该函数运行的模块,将导致
# 更新永远丢失。下次并行化
# 模块被复制,使用相同的随机初始化的向量!
# 广播并使用!
#
因此,为了使更改回传,我们依赖于两个
重要行为(也通过测试强制执行):
1. `DataParallel` 不克隆存储的广播张量
# 已在正确设备上;并且它确保
# 并行模块已经在`device[0]`上。
# 2. 如果`out=`参数中的输出张量具有正确的形状,它将
# 只需填充值即可。
# 因此,由于对所有元素都执行了相同的幂迭代,
仅更新张量而不改变设备,将确保设备上的模块副本更新_u 向量
在`device[0]`上的模块副本将通过共享存储来并行化模块
然而,在原地更新`u`和`v`之后,我们需要**克隆**
#
然而,在原地更新`u`和`v`之后,我们需要**克隆**
在使用之前先对它们进行归一化处理。这是为了支持
通过两次前向传递进行反向传播,例如,GAN 训练中的常见模式:
GAN 训练中的损失函数:损失 = D(real) - D(fake)。否则,引擎将
抱怨需要进行第一次前向传播的变量
(即第二个前向中的 u 和 v 向量)在第二个前向中发生变化。
预设条件
断言
权重矩阵.
维数 > 1
为 _
在
范围(
n 次幂迭代次数):
权重的谱范数等于 `u^T W v`,其中 `u` 和 `v`
是第一左和右奇异向量。
这种幂迭代产生 `u` 和 `v` 的近似值。
self._u = F.normalize(
火炬.mv(
权重矩阵, self.
下划线),
# 类型:忽略[has-type]
暗淡=0,
eps=self.eps,
输出=self._u,
# 类型:忽略[has-type]
)
self._v = F.normalize(
火炬.mv(
权重矩阵.H, self._u),
# 类型:忽略[has-type]
暗淡=0,
eps=self.eps,
输出=self.
下划线,
# 类型:忽略[has-type]
)
def 前向(self,
重量:
火炬.
张量) ->
火炬.
张量:
如果
重量.
维数 == 1:
更快更精确的路径,无需进行任何近似
返回 F.normalize(
重量,
暗淡=0, eps=self.eps)
否则:
weight_mat = self._reshape_weight_to_matrix(重量)
如果 self.
训练:
self.功率法(
权重矩阵, self.
n 次幂迭代)
# 请参阅上方,了解为何需要克隆
u = self._u.克隆(
内存格式=
火炬.
连续格式)
v = self.下划线.
克隆(
内存格式=
火炬.
连续格式)
正确计算此方法应该是通过 F.bilinear,但
# 它似乎存在一些效率问题:
# https://github.com/pytorch/pytorch/issues/58093
sigma
(由于 sigma 是数学和工程领域的通用符号,通常不进行翻译,因此保持原文不变。) = 火炬.
点积(u,
火炬.mv(
权重矩阵, v))
返回
权重 /
西格玛
def 右逆(self,
值:
火炬.
张量) ->
火炬.
张量:
#我们可能在这里断言传递的值已经
#满足约束
返回 value
[文档]def
谱范数(
模块:
模块,
名称:
字符串 =
权重,
n 次迭代功率:
整型 = 1,
eps: 浮点数 = 1e-12,
暗淡:
可选[int] =
无,
) -> 模块:
r将频谱归一化应用于给定模块中的参数。
.. math::
\mathbf{W}_{SN} = \dfrac{\mathbf{W}}{\sigma(\mathbf{W})},
\sigma(\mathbf{W}) = \max_{\mathbf{h}: \mathbf{h} \ne 0} \dfrac{\|\mathbf{W} \mathbf{h}\|_2}{\|\mathbf{h}\|_2},
当应用于向量时,它简化为。
.. math::
\mathbf{x}_{SN} = \dfrac{\mathbf{x}}{\|\mathbf{x}\|_2} = \dfrac{\mathbf{x}}{\sqrt{x_1^2 + x_2^2 + \cdots + x_n^2}}
光谱归一化稳定了判别器(评论家)的训练
通过降低 Lipschitz 常数在生成对抗网络(GANs)中
模型。:math:`σ` 通过执行一次迭代进行近似。
每次访问权重时使用`幂方法`。如果维度的
权重张量大于 2 时,在幂迭代中将其重塑为 2D
获取谱范数的方法。
请参阅《用于生成对抗网络的谱归一化》_ 。
.. _`幂方法`: https://en.wikipedia.org/wiki/Power_iteration
谱归一化用于生成对抗网络
.. 注意::
此函数使用参数化功能实现
在::func:`~torch.nn.utils.parametrize.register_parametrization`。它是一个
重新实现::func:`torch.nn.utils.spectral_norm`。
.. 注意::
当此约束被注册时,与最大奇异值关联的单个向量是估计的,而不是随机采样。
这些向量随后在执行 `power method`_ 的 :attr:`n_power_iterations` 次迭代时更新。
执行 :attr:`n_power_iterations` 次的 `power method`_ 操作。
以模块在 `训练` 模式下被访问。
.. 注意::
如果是 `_SpectralNorm` 模块,即 `module.parametrization.weight[idx]`,
在移除时处于训练模式,它将执行另一个幂迭代。
如果您想避免这个迭代,请将模块设置为评估模式。
在删除之前。
Args:
模块(nn.Module):包含模块。
名称(str,可选):权重参数的名称。默认值:``"weight"``。
n_power_iterations(int,可选):幂迭代次数。
计算谱范数。默认值:``1``。
eps (float, 可选): ε用于数值稳定性
计算范数。默认值:``1e-12``。
dim (int, 可选): 对应输出数量维度的整数。
默认:``0``,除非是实例化的模块
ConvTranspose{1,2,3}d,当其为``1``时
返回:
将具有新参数化的原始模块注册到指定的
权重
示例::
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_LAPACK)
>>> # xdoctest: +IGNORE_WANT("非确定性")
>>> snm = spectral_norm(nn.Linear(20, 40))
>>> snm
ParametrizedLinear(
in_features=20, out_features=40, bias=True
(parametrizations): ModuleDict(
(weight): ParametrizationList(
(0): _SpectralNorm()
)
)
)
>>> torch.linalg.matrix_norm(snm.weight, 2)
张量(1.0081, grad_fn=)
"源代码"
权重 = getattr(
模块,
名称,
无)
如果 not isinstance(
重量,
张量):
提升 ValueError(
f模块{
模块}
'没有名为'的参数或缓冲区{
名称}
)
如果
维度
是
无:
如果 isinstance(
模块,
(
火炬.nn.ConvTranspose1d,
火炬.nn.ConvTranspose2d,
火炬.nn.ConvTranspose3d,
),
):
维度 = 1
否则:
维度 = 0
参数化.
注册参数化(
模块,
名称,
_频谱归一(
重量,
n 次幂迭代次数,
暗淡, eps)
)
返回
模块