我有一个[batch_size, num_kernels, kernel_dim]
形状的张量。然后,我从中得出两个张量,一个为[batch_size, num_kernels, kernel_dim, 1]
形状,另一个为[1, num_kernels, kernel_dim, batch_size]
形状,然后从第一个中减去第二个张量,得到一个[batch_size, num_kernels, kernel_dim, batch_size]
形状(通过numpy,张量流,或其他)。如何解决?每个维度的含义是什么?例如,num_kernel
仍然将内核数表示为原始张量吗?为什么?
在这里出现我的问题。它基本上描述了Tim Salimans等在“改进的GAN训练技术”一文中引入的小批量歧视。
我不明白为什么tensorflow中的代码成功地计算了上面描述的过程。更具体地说,我想知道步骤2和3如何匹配代码。
答案 0 :(得分:0)
真的没有比the docs中的解释更好的解释了,但是我可以尝试总结一下。
将一个数组拟合到另一个数组以便可以在它们之间进行矢量化操作的过程称为“广播”。广播从右到右逐维度进行。对于每个维度:
例如,如果要执行x + y
,其中x
是20x10 2D数组:
y
也是20x10,则会将y
的每一行添加到x
中的相应行。并且,对于每个这样的行,它将y
行中的每一列添加到x
行中的相应列中。因此,结果是20x10。y
为1x10,则会将y
的单行添加到x
的20行中的每一行,并返回20x10的结果。y
为20x1,则通过将y
行中的每一列添加到x
中的每一列中,将y
的每一行添加到x
的行中y
行。同样,是20x10。y
为1x1,则通过将x
行中的单列添加到其中的每一列,将y
的单行添加到x
的每一行中x
行。就像将标量添加到y
一样。同样,是20x10。y
是10x1,这是一个值错误-1列可以广播到10列,但是10行不能广播到20行。y
是长度为10的一维数组,它将x
添加到y
的20行中的每行中,并返回20x10的结果-就像{{1} }是1x10。y
是30x20x10,则y
的30个20x10行中的每一行都将占整个20x10 x
的行,因此结果是30x20x10。y
为30x1x1,则会将y
的30个1x1行中的每行加到整个20x10 x
中,因此结果为30x20x10。y
是30x5x1,这是一个错误-可以广播1以匹配10,并且可以广播x
中缺少的尺寸以匹配30,但是5可以不能匹配20个。答案 1 :(得分:0)
将同一数组的两个版本相减的简单情况是:
In [208]: x = np.arange(10)
In [209]: x[None,:]-x[:,None]
Out[209]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8],
[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7],
[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6],
[-4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4],
[-6, -5, -4, -3, -2, -1, 0, 1, 2, 3],
[-7, -6, -5, -4, -3, -2, -1, 0, 1, 2],
[-8, -7, -6, -5, -4, -3, -2, -1, 0, 1],
[-9, -8, -7, -6, -5, -4, -3, -2, -1, 0]])
[209]
是(1,10)减去(10,1)产生(10,10)的情况。实际上,这是成对的差异。
因此,您的情况可能是批次之间的成对差异。如果您使用过,这对人类可能更清楚:
[1, batch_size, num_kernels, kernel_dim]
[batch_size, 1, num_kernels, kernel_dim]
[batch_size, batch_size, num_kernels, kernel_dim]
要测试您的评论,请从不同的维度开始:
In [210]: x = np.arange(2*3*4*5).reshape(2,3,4,5)
In [211]: np.sum(x,0).shape
Out[211]: (3, 4, 5)
In [212]: np.transpose(np.sum(x,0),[2,0,1]).shape
Out[212]: (5, 3, 4)
In [214]: np.sum(x,3).shape
Out[214]: (2, 3, 4)
形状不匹配,所以总和也不一样。
答案 2 :(得分:0)
如果我错了,别怪我。
假设您有两个分别具有形状X
和Y
的二维矩阵(x, n)
和(y, n)
,并且您要计算L1距离。您可能想要做类似的事情
np.abs(X[:, None, :] - Y).sum(-1)
或
np.abs(np.expand_dims(X, -1) - np.expand_dims(Y.transpose(1, 0), 0)).sum(1)
它们通过不同的广播方式产生相同的结果:
我认为更简单的第一个计算如下,
(x, 1, n) - (y, n) => (x, y, n) => (x, y)
我相信的第二个只是您发布的代码的简单版本,像这样计算
(x, n, 1) - (1, y, n) => (x, n, y) => (x, y)
这里的关键点是:对于这样的成对差异,为了产生形状为(x, y)
的结果,您需要添加一个额外的尺寸并进行一些广播。
对于您而言,x
和y
均为batch_size
。如果您询问它们的含义,我会说:“第一个batch_size
表示来自,第二个batch_size
表示至。{{1 }}就是从批次中的第一个样品到批次中的第二个样品的距离。“
答案 3 :(得分:0)
最难理解的部分应该是
diffs = tf.expand_dims(x, 3) - tf.expand_dims(tf.transpose(x, [1, 2, 0]), 0)
如果我们固定第一个维度,则事情将会很清楚,即(为清楚起见,在这里,我使用numpy表示法,并使用y
和z
来表示转换后的x
)>
diffs[k] = y[i, :, :, 1] - z[1, :, :, :]
其中有y[i, m, n] = [x[i, m, n]]
和z[1, m, n, j]=x[j, m, n]
。现在,我们广播y
和z
,对于任何y[i, m, n, j]=x[i, m, n]
,我们将拥有j
,对于任何z[i, m, n, j]=x[j, m, n]
,我们将具有i
。对于固定的i
和'j',如果我们从z
中减去y
,则等效地从x[i, m, n]
中减去x[j, m, n]
,即(M_ {i ,b} -M_ {j,b}在步骤2中