我有一个 PyTorch 张量,并且想 在优化时对其元素施加等式约束。下面显示了一个 2 * 9 张量的示例,其中相同的颜色表示元素应该始终相等。
我们做一个1 * 4的最小例子,分别初始化前两个和后两个元素相等
import torch
x1 = torch.tensor([1.2, 1.2, -0.3, -0.3])
print(x1)
# tensor([ 1.2000, 1.2000, -0.3000, -0.3000])
如果我直接做一个简单的最小二乘,等式肯定不存在了
y = torch.arange(4)
opt_1 = torch.optim.SGD([x1], lr=0.1)
opt_1.zero_grad()
loss = (y - x1).pow(2).sum()
loss.backward()
opt_1.step()
print(x1)
# tensor([0.9600, 1.1600, 0.1600, 0.3600], requires_grad=True)
我试图将这个张量表示为掩码的加权和.
def weighted_sum(c, masks):
return torch.sum(torch.stack([c[0] * masks[0], c[1] * masks[1]]), axis=0)
c = torch.tensor([1.2, -0.3], requires_grad=True)
masks = torch.tensor([[1, 1, 0, 0], [0, 0, 1, 1]])
x2 = weighted_sum(c, masks)
print(x2)
# tensor([ 1.2000, 1.2000, -0.3000, -0.3000])
这样优化后等式依然存在
opt_c = torch.optim.SGD([c], lr=0.1)
opt_c.zero_grad()
y = torch.arange(4)
x2 = weighted_sum(c, masks)
loss = (y - x2).pow(2).sum()
loss.backward()
opt_c.step()
print(c)
# tensor([0.9200, 0.8200], requires_grad=True)
print(weighted_sum(c, masks))
# tensor([0.9200, 0.9200, 0.8200, 0.8200], grad_fn=<SumBackward1>)
但是,这个解决方案最大的问题是当输入维度很高时,我必须维护一大组masks;肯定会导致内存不足。假设输入张量的形状是
d_0 * d_1 * ... * d_m
,相等块的个数是k
,那么就会有一个巨大的k * d_0 * d_1 * ... * d_m
形状的mask,这是不可接受的。
另一个解决方案可能是升采样像这个这样的低分辨率张量。但是,它不能应用于不规则的相等块,例如,
tensor([[ 1.2000, 1.2000, 1.2000, -3.1000, -3.1000],
[-0.1000, 2.0000, 2.0000, 2.0000, 2.0000]])
那么...有没有更聪明的方法在 PyTorch 张量中实现这种等式约束?
如果您希望它们始终相等,为什么不从
x
和y
中删除第一个和最后一个值?额外的值可以在训练后需要时从模型输出中导出,因为无论如何它们都应该等于它们的邻居。无需学习相同值的两个副本。
如果你想更近似地了解它们是相同的,你可以将
some_weight * (torch.abs(x[0]-x[1]) + torch.abs(x[-1] - x[-2]))
添加到你的损失函数中。那么你的损失将是试图了解这些预计是相同的。
或者,如果您对每个值都有计数,而不是掩码,也许您正在寻找这样的东西?
def convert(tensor, counts):
return torch.cat( [v.repeat(count) for (v, count) in zip(tensor, counts) ] )
convert( torch.arange(4), [3,2,1,3])
tensor([0, 0, 0, 1, 1, 2, 3, 3, 3])