假设我有一个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 = 1,我想排除(例如)L = 35之后的所有数据。对于切片N = 2(例如),所有数据均有效。对于切片N = 3,排除L = 30之后的所有数据,依此类推。这模拟了具有多个特征但长度不相同的一维时间序列数据。
如何在PyTorch中对此类数据执行实例规范,获取正确的统计信息并维护差异性/ AutoGrad信息?
更新:在保持GPU性能的同时,或者至少不会使其死亡。
我不能...
我错过了可以满足我需求的方法吗?还是我错过了一种数据重新排列的方法,该方法可以使上面的3或4起作用?
这是循环神经网络一直面临的一个问题,因此pack_padded_sequence功能,但在这里并不十分适用。
答案 0 :(得分:1)
我认为不可能直接使用现有的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