假设我想优化一个向量
v
,使其范数等于 1。为此,我使用该向量定义了一个网络,如下所示:
class myNetwork(nn.Module):
def __init__(self,initial_vector):
super(myNetwork, self).__init__()
#Define vector according to an initial column vector
self.v = nn.Parameter(initial_vector)
def forward(self,x):
#Normalize vector so that its norm is equal to 1
self.v.data = self.v.data / torch.sqrt(self.v.data.transpose(1,0) @ self.v.data)
#Multiply v times a row vector
out = x @ self.v
return out
使用
.data
是更新v
的最佳方式吗?它是否考虑了反向传播期间的归一化?
您可以简单地使用
def forward(self,x):
return x @ self.v / (x**2).sum()
根据您的损失或网络的下游层,甚至完全跳过标准化。
def forward(self,x):
return x @ self.v
只要你的损失在规模上不变,这个方法就应该有效,标准每一步应该只有轻微的变化,但它并不严格稳定。如果你给出了很多步骤,也许值得在你的损失中添加一个术语
thinyvalue * ((myNetwork.v**2).sum()-1)**2
,以确保 $v$ 的范数被吸引到 1。
您可以使用 pytorch 参数化。您可以首先定义以下 nn.Module,它将向量作为输入,返回相同的向量除以其范数(即范数 1 向量):
class NormalizeVector(nn.Module):
def forward(self, eta):
theta = eta / eta.norm()
return theta
然后您只需在您定义的类中的参数上注册此参数化,并在转发调用中省略规范化:
from torch.nn.utils import parametrize
class myNetwork(nn.Module):
def __init__(self,initial_vector):
super(myNetwork, self).__init__()
self.v = nn.Parameter(initial_vector)
parametrize.register_parametrization(self, "v", NormalizeVector())
def forward(self,x):
#Multiply v times a row vector
out = x @ self.v
return out
参数化将使向量
v
保持单位长度。您可以使用相同的训练代码,并像其他方式一样访问 v
。您可以在此处查看更长的参数化教程。