两个具有不同形状的张量相减的结果是什么意思?

时间:2018-08-19 23:20:50

标签: python numpy tensor

我有一个[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训练技术”一文中引入的小批量歧视。

enter image description here

我不明白为什么tensorflow中的代码成功地计算了上面描述的过程。更具体地说,我想知道步骤2和3如何匹配代码。

4 个答案:

答案 0 :(得分:0)

真的没有比the docs中的解释更好的解释了,但是我可以尝试总结一下。

将一个数组拟合到另一个数组以便可以在它们之间进行矢量化操作的过程称为“广播”。广播从右到右逐维度进行。对于每个维度:

  • 如果两个数组在该维度上的大小相同...那么,这很明显。
  • 如果一个数组在该维度上的大小为1,则会被重复。
  • 如果其中一个数组的尺寸用完了,则将其视为其余所有尺寸中的1个。

例如,如果要执行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)

如果我错了,别怪我。

假设您有两个分别具有形状XY的二维矩阵(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)

它们通过不同的广播方式产生相同的结果:

  1. 我认为更简单的第一个计算如下,

    (x, 1, n) - (y, n) => (x, y, n) => (x, y)

  2. 我相信的第二个只是您发布的代码的简单版本,像这样计算

    (x, n, 1) - (1, y, n) => (x, n, y) => (x, y)

这里的关键点是:对于这样的成对差异,为了产生形状为(x, y)的结果,您需要添加一个额外的尺寸并进行一些广播。

对于您而言,xy均为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表示法,并使用yz来表示转换后的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]。现在,我们广播yz,对于任何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中