Python 使用numpy方法修改(keras/tensorflow)张量

Python 使用numpy方法修改(keras/tensorflow)张量,python,numpy,tensorflow,keras,Python,Numpy,Tensorflow,Keras,我想执行一个特定的操作。即,从矩阵中: A = np.array([[1,2], [3,4]]) 以下 B = np.array([[1, 0, 0, 2, 0, 0], [0, 1, 0, 0, 2, 0], [0, 0, 1, 0, 0, 2], [3, 0, 0, 4, 0, 0], [0, 3, 0, 0, 4, 0], [

我想执行一个特定的操作。即,从矩阵中:

A = np.array([[1,2],
            [3,4]])
以下

B = np.array([[1, 0, 0, 2, 0, 0],
              [0, 1, 0, 0, 2, 0],
              [0, 0, 1, 0, 0, 2],
              [3, 0, 0, 4, 0, 0],
              [0, 3, 0, 0, 4, 0],
              [0, 0, 3, 0, 0, 4]])
或者换句话说:将每个条目乘以单位矩阵,并保持相同的顺序。 现在,我已经通过使用numpy完成了这项工作,使用了以下代码。这里
N
M
是起始矩阵的维数和单位矩阵的维数

l_slice = 3
n_slice = 2
A = np.reshape(np.arange(1, 1+N ** 2), (N, N))
B = np.array([i * np.eye(M) for i in A.flatten()])
C = B.reshape(N, N, M, M).reshape(N, N * M, M).transpose([0, 2, 1]).reshape((N * M, N * M))
其中
C
具有我所需的属性

但是现在我想在Keras/Tensorflow中做这个修改,其中矩阵
A
是我的一个层的结果

然而,我还不确定我是否能够正确地创建矩阵B。特别是当涉及批次时,我想我会以某种方式搞乱问题的维度。
任何拥有更多Keras/Tensorflow经验的人都可以对这种“重塑”以及他/她如何看待Keras/Tensorflow内部发生的这种情况发表评论吗?

以下是一种使用Tensorflow的方法:

import tensorflow as tf

data = tf.placeholder(tf.float32, [None, None])
n = tf.placeholder(tf.int32, [])
eye = tf.eye(n)
mult = data[:, tf.newaxis, :, tf.newaxis] * eye[tf.newaxis, :, tf.newaxis, :]
result = tf.reshape(mult, n * tf.shape(data))
with tf.Session() as sess:
    a = sess.run(result, feed_dict={data: [[1, 2], [3, 4]], n: 3})
    print(a)
输出:

[[1.0.0.2.0.0]
[0. 1. 0. 0. 2. 0.]
[0. 0. 1. 0. 0. 2.]
[3. 0. 0. 4. 0. 0.]
[0. 3. 0. 0. 4. 0.]
[0. 0. 3. 0. 0. 4.]]
顺便说一下,您可以在NumPy中执行基本相同的操作,这应该比您当前的解决方案更快:

import numpy as np

data = np.array([[1, 2], [3, 4]])
n = 3
eye = np.eye(n)
mult = data[:, np.newaxis, :, np.newaxis] * eye[np.newaxis, :, np.newaxis, :]
result = np.reshape(mult, (n * data.shape[0], n * data.shape[1]))
print(result)
# The output is the same as above

编辑:

我将试着给出一些关于为什么/如何工作的直觉,抱歉,如果时间太长了。这并不难,但我认为解释起来有点棘手。也许更容易看到下面的乘法是如何工作的

import numpy as np

data = np.array([[1, 2], [3, 4]])
n = 3
eye = np.eye(n)
mult1 = data[:, :, np.newaxis, np.newaxis] * eye[np.newaxis, np.newaxis, :, :]
现在,
mult1
是一种“矩阵的矩阵”。如果我给出两个索引,我将得到原始索引中对应元素的对角矩阵:

print(mult1[0, 0])
# [[1. 0. 0.]
#  [0. 1. 0.]
#  [0. 0. 1.]]
所以你可以说这个矩阵可以像这样可视化:

| 1 0 0 |  | 2 0 0 |
| 0 1 0 |  | 0 2 0 |
| 0 0 1 |  | 0 0 2 |

| 3 0 0 |  | 4 0 0 |
| 0 3 0 |  | 0 4 0 |
| 0 0 3 |  | 0 0 4 |
然而,这是一种欺骗,因为如果您试图将其重塑为最终形状,结果并不正确:

print(np.reshape(mult1, (n * data.shape[0], n * data.shape[1])))
# [[1. 0. 0. 0. 1. 0.]
#  [0. 0. 1. 2. 0. 0.]
#  [0. 2. 0. 0. 0. 2.]
#  [3. 0. 0. 0. 3. 0.]
#  [0. 0. 3. 4. 0. 0.]
#  [0. 4. 0. 0. 0. 4.]]
原因是重塑(概念上)首先“展平”阵列,然后给出新的形状。但在这种情况下,展平阵列不是您需要的:

print(mult1.ravel())
# [1. 0. 0. 0. 1. 0. 0. 0. 1. 2. 0. 0. 0. 2. 0. ...
你看,它首先遍历第一个子矩阵,然后遍历第二个子矩阵,等等。你想让它遍历第一个子矩阵的第一行,然后遍历第二个子矩阵的第一行,然后遍历第一个子矩阵的第二行,等等。所以基本上你想要这样的东西:

  • 取前两个子矩阵(分别为
    1
    2
    • 取所有第一行(
      [1,0,0]
      [2,0,0]
      )。
      • 取第一个(
        [1,0,0]
        • 取其每个元素(
          1
          0
          0
然后继续剩下的。如果你仔细想想,我们首先遍历轴0(矩阵矩阵的行),然后遍历2(每个子矩阵的行),然后遍历1(矩阵矩阵的列),最后遍历3(子矩阵的列)。因此,我们可以对轴进行重新排序:

mult2 = mult1.transpose((0, 2, 1, 3))
print(np.reshape(mult2, (n * data.shape[0], n * data.shape[1])))
# [[1. 0. 0. 2. 0. 0.]
#  [0. 1. 0. 0. 2. 0.]
#  [0. 0. 1. 0. 0. 2.]
#  [3. 0. 0. 4. 0. 0.]
#  [0. 3. 0. 0. 4. 0.]
#  [0. 0. 3. 0. 0. 4.]]
而且它有效!因此,在我发布的解决方案中,为了避免变换,我只进行了乘法,因此轴的顺序正好是:

mult = data[
        :,           # Matrix-of-matrices rows
        np.newaxis,  # Submatrix rows
        :,           # Matrix-of-matrices columns
        np.newaxis   # Submatrix columns
    ] * eye[
        np.newaxis,  # Matrix-of-matrices rows
        :,           # Submatrix rows
        np.newaxis,  # Matrix-of-matrices columns
        :            # Submatrix columns
    ]

我希望这能让事情变得更清楚一点。老实说,在这种情况下,我可以很快想出解决方案,因为不久前我不得不解决一个类似的问题,我猜你最终会对这些事情产生直觉。

在numpy中实现相同效果的另一种方法是使用以下方法:

A = np.array([[1,2],
            [3,4]])
B = np.repeat(np.repeat(A, 3, axis=0), 3, axis=1) * np.tile(np.eye(3), (2,2))
然后,为了在tensorflow中复制它,我们可以使用
tf.tile
,但是没有
tf.repeat
,但是有人在上提供了这个函数

因此,tensorflow的实现如下所示。在这里,我还认为第一个维度代表批次,因此我们不操作它。

N = 2
M = 3
nbatch = 2
Ain = np.reshape(np.arange(1, 1 + N*N*nbatch), (nbatch, N, N))

A = tf.placeholder(tf.float32, shape=(nbatch, N, N))
B = tf.tile(tf.eye(M), [N, N]) * tf_repeat(A, [1, M, M])

with tf.Session() as sess:
    print(sess.run(C, feed_dict={A: Ain}))
结果是:

 [[[1. 0. 0. 2. 0. 0.]
  [0. 1. 0. 0. 2. 0.]
  [0. 0. 1. 0. 0. 2.]
  [3. 0. 0. 4. 0. 0.]
  [0. 3. 0. 0. 4. 0.]
  [0. 0. 3. 0. 0. 4.]]

 [[5. 0. 0. 6. 0. 0.]
  [0. 5. 0. 0. 6. 0.]
  [0. 0. 5. 0. 0. 6.]
  [7. 0. 0. 8. 0. 0.]
  [0. 7. 0. 0. 8. 0.]
  [0. 0. 7. 0. 0. 8.]]]

啊,谢谢,是的,因为我在tensorflow中找不到repeat函数,所以我想要一个没有它的解决方案。但很高兴知道有一个实现它!啊,是的,在我心里,我知道应该是这样的。但是我没有想到以这种方式使用np.newaxis的解决方案。谢谢只有一个子问题。。。你能解释一下你是怎么想出这个矩阵乘法的方法的吗?因为我似乎无法在脑海中“想象”解决方案。。这意味着我不明白解决方案fully@zwep我添加了一些解释,希望能有所帮助。啊,是的,非常感谢,特别是关于如何解释4d阵列轴的部分。你回复的速度也让我大吃一惊,所以谢谢你的最后一个注释,哈哈。最后一个注释(据我所知…)为了正确处理批处理维度,我在创建的标识矩阵上使用了tf.expand_dims()。使用tf.newaxis的AFAIK应该会产生类似的结果,但建议在处理可变批次维度时使用此结果。
 [[[1. 0. 0. 2. 0. 0.]
  [0. 1. 0. 0. 2. 0.]
  [0. 0. 1. 0. 0. 2.]
  [3. 0. 0. 4. 0. 0.]
  [0. 3. 0. 0. 4. 0.]
  [0. 0. 3. 0. 0. 4.]]

 [[5. 0. 0. 6. 0. 0.]
  [0. 5. 0. 0. 6. 0.]
  [0. 0. 5. 0. 0. 6.]
  [7. 0. 0. 8. 0. 0.]
  [0. 7. 0. 0. 8. 0.]
  [0. 0. 7. 0. 0. 8.]]]