Модификация (керас / тензор потока) тензоров с использованием цифровых методов - PullRequest
0 голосов
/ 31 октября 2018

Я хочу выполнить определенную операцию. А именно, из матрицы:

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?

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Другим способом достижения того же эффекта в 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))

Затем, чтобы реплицировать его в тензор потока, мы можем использовать tf.tile, но tf.repeat нет, однако кто-то предоставил эту функцию на трекер тензор потока .

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

и, следовательно, реализация tenorflow будет выглядеть следующим образом. Здесь я также считаю, что первое измерение представляет партии, и поэтому мы не работаем с ним.

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.]]]
0 голосов
/ 31 октября 2018

Вот способ сделать это с 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

EDIT:

Я попытаюсь дать некоторую интуицию о том, почему / как это работает, извините, если это слишком долго. Это не так сложно, но я думаю, что это сложно объяснить. Может быть, легче увидеть, как работает следующее умножение

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
    ]

Надеюсь, это немного прояснит. Честно говоря, в этом случае, в частности, я мог быстро найти решение, потому что мне пришлось решать аналогичную проблему не так давно, и я полагаю, что в итоге вы создали интуицию из этих вещей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...