基于方差/标准差矩阵的高斯噪声破坏张量
Corrupting Tensor with Gaussian Noise based on a Variance / Stddev Matrix
我有一个 CNN 输出掩码 (logits
, shape = [batch, x, y, classes]
) 和一个矩阵 (sigma
) 将高斯噪声的标准差分配给每个 logit(即 sigma.shape = [x, y, classes]
)。 我想根据相应的 sigma 用高斯噪声破坏每个 logit。 在 tensorflow 中,我只找到了一个适用于标量的高斯:tf.random_normal
。
因此我使用循环,"computed" 分别为每个 logit 噪声(mean = logit[b, x, y, c]
,stddev = sigma[x, y, c]
)并使用 tf.stack
取回我的 4-D 张量。但是:对于 [1, 1024, 1024, 2]
-Tensor 这已经需要很长时间了(在 "didn't finish" 的范围内),我想这是有道理的,因为它必须创建和堆叠> 100 万个张量对象。
无论如何,我很确定这不是要走的路...
但是我应该怎么做呢? 是否有tf.random_normal
允许在更高维度上工作?
我知道 tf.random_normal
可以 return 具有(任意)shape
的更多维张量,但这对我不起作用,因为它对每个张量应用相同的 stddev元素(均值无关紧要,因为我可以生成 0 均值噪声和 tf.add()
)。
如果它以任何方式相关:我现在可以接受的妥协(为了加快速度)是使用仅基于像素的 stddev 生成噪声(而不是 class ),即 *sigma.shape = [x, y]
*。但这只消除了一个循环而不是主要问题 (x*y).
此处是 "loop" 方法的代码。我测试了它的小值([1, 8, 8, 2]
。我知道我可以省去 for b
循环,但这不是 "meat" 成本,x*y 计算才是真正的问题:
logits = self.output_mask # e.g. shape: [1, 1024, 1024, 2]
sigma = tf.ones(shape=[1024, 1024, 2], dtype=logits.dtype) # dummy values, will be a learned parameter later
corrupted_logits_b = []
for b in range(logits.shape[0]):
corrupted_logits_x = []
for x in range(logits.shape[1]):
corrupted_logits_y = []
for y in range(logits.shape[2]):
corrupted_logits_c = []
for c in range(logits.shape[3]):
# this is where the noise is computed
# (added to the logit since mean = logit)
corrupted_logit = tf.random_normal(tf.shape(logits[b, x, y, c]),
mean=logits[b, x, y, c],
stddev=sigma_val[x, y, c])
# "values"/logit-tensors are appended to lists and
# ... and stacked to form higher-dim tensors
corrupted_logits_c.append(corrupted_logit)
corrupted_logits_y.append(tf.stack(corrupted_logits_c, axis=-1))
corrupted_logits_x.append(tf.stack(corrupted_logits_y))
corrupted_logits_b.append(tf.stack(corrupted_logits_x))
corrupted_logits = tf.stack(corrupted_logits_b, axis=-1)
所以我实际上找到了一个很好的解决方法,使用正态分布 N(0, 1)
乘以 σ (sigma)与正态分布相同 with stddev
σ (sigma) N(0, σ**2)
:
N(0,σ**2) = N(0,1)⋅σ
因此你可以这样做:
# sigma can be of shape of logits or needs to be broadcastable
sigma = tf.Placeholder(shape=tf.shape(logits), dtype=logits.dtype)
def corrupt_logits(logits, sigma):
# generate a normal distribution N(0,1) of desired shape (4D in my case)
gaussian = tf.random_normal(tf.shape(logits), mean=0.0, stddev=1.0, dtype=logits.dtype)
# turn into normal distribution N(0,σ**2) by multiplying with σ
# since sigma is a 4D tensor of tf.shape(logits), it can "assign" an individual σ to each logit
noise = tf.multiply(gaussian, sigma)
# add zero-mean/stddev-σ noise to logits
return tf.add(logits, noise)
这会比 for-loops 好很多,并且支持各种变体,因为如果某个维度的 sigma 相同(例如,每个 x、y 仅不同),它会自动广播其他维度(例如 batch_size、类)。
我有一个 CNN 输出掩码 (logits
, shape = [batch, x, y, classes]
) 和一个矩阵 (sigma
) 将高斯噪声的标准差分配给每个 logit(即 sigma.shape = [x, y, classes]
)。 我想根据相应的 sigma 用高斯噪声破坏每个 logit。 在 tensorflow 中,我只找到了一个适用于标量的高斯:tf.random_normal
。
因此我使用循环,"computed" 分别为每个 logit 噪声(mean = logit[b, x, y, c]
,stddev = sigma[x, y, c]
)并使用 tf.stack
取回我的 4-D 张量。但是:对于 [1, 1024, 1024, 2]
-Tensor 这已经需要很长时间了(在 "didn't finish" 的范围内),我想这是有道理的,因为它必须创建和堆叠> 100 万个张量对象。
无论如何,我很确定这不是要走的路...
但是我应该怎么做呢? 是否有tf.random_normal
允许在更高维度上工作?
我知道 tf.random_normal
可以 return 具有(任意)shape
的更多维张量,但这对我不起作用,因为它对每个张量应用相同的 stddev元素(均值无关紧要,因为我可以生成 0 均值噪声和 tf.add()
)。
如果它以任何方式相关:我现在可以接受的妥协(为了加快速度)是使用仅基于像素的 stddev 生成噪声(而不是 class ),即 *sigma.shape = [x, y]
*。但这只消除了一个循环而不是主要问题 (x*y).
此处是 "loop" 方法的代码。我测试了它的小值([1, 8, 8, 2]
。我知道我可以省去 for b
循环,但这不是 "meat" 成本,x*y 计算才是真正的问题:
logits = self.output_mask # e.g. shape: [1, 1024, 1024, 2]
sigma = tf.ones(shape=[1024, 1024, 2], dtype=logits.dtype) # dummy values, will be a learned parameter later
corrupted_logits_b = []
for b in range(logits.shape[0]):
corrupted_logits_x = []
for x in range(logits.shape[1]):
corrupted_logits_y = []
for y in range(logits.shape[2]):
corrupted_logits_c = []
for c in range(logits.shape[3]):
# this is where the noise is computed
# (added to the logit since mean = logit)
corrupted_logit = tf.random_normal(tf.shape(logits[b, x, y, c]),
mean=logits[b, x, y, c],
stddev=sigma_val[x, y, c])
# "values"/logit-tensors are appended to lists and
# ... and stacked to form higher-dim tensors
corrupted_logits_c.append(corrupted_logit)
corrupted_logits_y.append(tf.stack(corrupted_logits_c, axis=-1))
corrupted_logits_x.append(tf.stack(corrupted_logits_y))
corrupted_logits_b.append(tf.stack(corrupted_logits_x))
corrupted_logits = tf.stack(corrupted_logits_b, axis=-1)
所以我实际上找到了一个很好的解决方法,使用正态分布 N(0, 1)
乘以 σ (sigma)与正态分布相同 with stddev
σ (sigma) N(0, σ**2)
:
N(0,σ**2) = N(0,1)⋅σ
因此你可以这样做:
# sigma can be of shape of logits or needs to be broadcastable
sigma = tf.Placeholder(shape=tf.shape(logits), dtype=logits.dtype)
def corrupt_logits(logits, sigma):
# generate a normal distribution N(0,1) of desired shape (4D in my case)
gaussian = tf.random_normal(tf.shape(logits), mean=0.0, stddev=1.0, dtype=logits.dtype)
# turn into normal distribution N(0,σ**2) by multiplying with σ
# since sigma is a 4D tensor of tf.shape(logits), it can "assign" an individual σ to each logit
noise = tf.multiply(gaussian, sigma)
# add zero-mean/stddev-σ noise to logits
return tf.add(logits, noise)
这会比 for-loops 好很多,并且支持各种变体,因为如果某个维度的 sigma 相同(例如,每个 x、y 仅不同),它会自动广播其他维度(例如 batch_size、类)。