PyTorch中的掩蔽和实例规范化
假设我有一个PyTorch张量,排列为[N,C,L]形,其中N是批量大小,C是通道或特征的数量,L是长度。在这种情况下,如果希望执行实例规范化,可以执行以下操作:PyTorch中的掩蔽和实例规范化,pytorch,normalization,Pytorch,Normalization,假设我有一个PyTorch张量,排列为[N,C,L]形,其中N是批量大小,C是通道或特征的数量,L是长度。在这种情况下,如果希望执行实例规范化,可以执行以下操作: N = 20 C = 100 L = 40 m = nn.InstanceNorm1d(C, affine=True) input = torch.randn(N, C, L) output = m(input) 这将对每个N*C=2000个数据切片在L维中执行标准化,减去2000个平均值,按2000个标准偏差进行缩放,并按100
N = 20
C = 100
L = 40
m = nn.InstanceNorm1d(C, affine=True)
input = torch.randn(N, C, L)
output = m(input)
这将对每个N*C=2000个数据切片在L维中执行标准化,减去2000个平均值,按2000个标准偏差进行缩放,并按100个可学习的权重和偏差参数(每个通道一个)重新缩放。这里的潜台词是,所有这些价值观都存在并有意义
但是我有一种情况,对于切片N=1,我想排除(比如)L=35之后的所有数据。对于切片N=2(假设),所有数据都有效。对于切片N=3,排除L=30之后的所有数据,以此类推。这模拟了一维时间序列的数据,具有多个特征,但长度不同
如何对此类数据执行实例规范,获得正确的统计数据,并在PyTorch中维护可微性/自动标记信息?
更新:在保持GPU性能的同时,或者至少不让它死机。
我不能
这是递归神经网络一直面临的问题,因此具有pack_-padded_序列功能,但在这里不太适用 我认为使用现有的
InstanceNorm1d
无法直接实现,最简单的方法可能是自己从头开始实现。我做了一个快速的实现,应该可以工作。为了使它更通用一点,这个模块需要一个布尔掩码(与输入大小相同的布尔张量),指定在通过实例范数时应该考虑哪些元素
import torch
class MaskedInstanceNorm1d(torch.nn.Module):
def __init__(self, num_features, eps=1e-6, momentum=0.1, affine=True, track_running_stats=False):
super().__init__()
self.num_features = num_features
self.eps = eps
self.momentum = momentum
self.affine = affine
self.track_running_stats = track_running_stats
self.gamma = None
self.beta = None
if self.affine:
self.gamma = torch.nn.Parameter(torch.ones((1, self.num_features, 1), requires_grad=True))
self.beta = torch.nn.Parameter(torch.zeros((1, self.num_features, 1), requires_grad=True))
self.running_mean = None
self.running_variance = None
if self.affine:
self.running_mean = torch.zeros((1, self.num_features, 1), requires_grad=True)
self.running_variance = torch.zeros((1, self.num_features, 1), requires_grad=True)
def forward(self, x, mask):
mean = torch.zeros((1, self.num_features, 1), requires_grad=False)
variance = torch.ones((1, self.num_features, 1), requires_grad=False)
# compute masked mean and variance of batch
for c in range(self.num_features):
if mask[:, c, :].any():
mean[0, c, 0] = x[:, c, :][mask[:, c, :]].mean()
variance[0, c, 0] = (x[:, c, :][mask[:, c, :]] - mean[0, c, 0]).pow(2).mean()
# update running mean and variance
if self.training and self.track_running_stats:
for c in range(self.num_features):
if mask[:, c, :].any():
self.running_mean[0, c, 0] = (1-self.momentum) * self.running_mean[0, c, 0] \
+ self.momentum * mean[0, c, 0]
self.running_variance[0, c, 0] = (1-self.momentum) * self.running_variance[0, c, 0] \
+ self.momentum * variance[0, c, 0]
# compute output
x = (x - mean)/(self.eps + variance).sqrt()
if self.affine:
x = x * self.gamma + self.beta
return x
我是否正确理解您,如果您指定排除最后35个条目,您不希望更新
InstanceNorm
s最后35个权重(和偏差)?您如何在其他模块中处理这些最后35个值?(比如Conv1d
或者Linear
等等?@failfr不是我不想让它们更新(虽然从技术上说它们不应该更新)。而是标准化依赖于均值和方差的计算,我想让计算忽略屏蔽值。例如,[1,2,3,4,5,__________;应在平均值为3和总体方差为2的基础上进行标准化,而不管用____;表示的屏蔽值是什么。@r经过计算后,它们将从损失函数中屏蔽。如果有必要,重新设置为零也是一种选择。Sot huis意味着对于通过修改的InstanceForm
的每一批,您也会传递一个索引列表/张量(大小NxC
),这些索引定义了哪些值是相关的,哪些值应该被屏蔽,对吗?我得出了相同的结论,如果不实施或重新实施某些东西,就无法实现。我怀疑将nanmean和nanvar添加到torch中,并有条不紊地将它们扩展到规范化例程中,是最干净的方法,但这超出了我的时间投资范围。此外,这方面的语义(特别是循环指数)并不完全正确,但它们很容易修补以提供正确的行为。我将对此进行思考和基准测试,同时希望其他人看到我错过的东西。@Novak王到底是什么?我对它进行了测试,它的工作原理与我们讨论的一样,在更新中只考虑屏蔽条目,而未屏蔽条目基本上通过一个标识;简单的解释需要在某些位置嵌套循环。制作一个形状为[3,2,4]的随机张量,并使用InstanceNorm1d()的默认实现对其进行测试。如果掩码张量设置为all True,您应该会看到相同的结果,但您不会看到。而且-,这也是我真正担心的-,GPU设备上的性能会因为这些循环而下降。