【问题标题】:Modifying (keras/tensorflow) Tensors using numpy methods使用 numpy 方法修改(keras/tensorflow)张量
【发布时间】:2019-04-04 16:49:57
【问题描述】:

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

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 完成了这个,使用下面的代码。这里NM是起始矩阵的维数,也是单位矩阵的维数。

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 中发生的这种情况吗?

【问题讨论】:

    标签: python numpy tensorflow keras


    【解决方案1】:

    这是使用 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. ...
    

    你看,它首先遍历第一个子矩阵,然后是第二个,等等。但你想要的是它首先遍历第一个子矩阵的第一行,然后是第二个子矩阵的第一行,然后是第二行第一个子矩阵等。所以基本上你想要这样的东西:

    • 取前两个子矩阵(带有12 的子矩阵)
      • 获取所有第一行([1, 0, 0][2, 0, 0])。
        • 采取其中的第一个 ([1, 0, 0])
          • 获取其中的每个元素(100)。

    然后继续剩下的。因此,如果您考虑一下,我们首先遍历轴 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
        ]
    

    我希望这能让它更清晰一些。老实说,特别是在这种情况下,我可以很快想出解决方案,因为不久前我必须解决一个类似的问题,我猜你最终会建立对这些事情的直觉。

    【讨论】:

    • 啊,是的,在我看来,我知道它应该是这样的。但是我没有想到以这种方式使用 np.newaxis 的解决方案。谢谢!
    • 只是一个子问题...您能以某种方式解释您提出这种矩阵乘法的方法吗?因为我似乎无法在脑海中“想象”解决方案..所以这意味着我不完全理解解决方案
    • @zwep 我已经添加了一些解释,希望对您有所帮助。
    • 啊,是的,非常感谢,尤其是关于如何解释 4d 数组的轴的部分。你回复的速度也吓到我了,谢谢你最后的留言,哈哈。
    • 最后一点(据我所知..)为了正确处理批处理维度,我在创建的单位矩阵上使用了 tf.expand_dims() 。使用 tf.newaxis 的 AFAIK 应该会产生类似的结果,但建议在处理可变批次维度时使用此结果。
    【解决方案2】:

    在 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 tracker上提供了这个功能。

    def tf_repeat(tensor, repeats):
        """
        Args:
    
        input: A Tensor. 1-D or higher.
        repeats: A list. Number of repeat for each dimension, length must be the same as the number of dimensions in input
    
        Returns:
    
        A Tensor. Has the same type as input. Has the shape of tensor.shape * repeats
        """
        with tf.variable_scope("repeat"):
            expanded_tensor = tf.expand_dims(tensor, -1)
            multiples = [1] + list(repeats)
            tiled_tensor = tf.tile(expanded_tensor, multiples=multiples)
            repeated_tesnor = tf.reshape(tiled_tensor, tf.shape(tensor) * repeats)
        return repeated_tesnor
    

    因此 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 中找不到重复函数,所以我想要一个没有它的解决方案。但很高兴知道它有一个实现!
    猜你喜欢
    • 1970-01-01
    • 2020-06-12
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多