Векторизация умножения матриц с различными формами в numy / tenorflow - PullRequest
1 голос
/ 11 ноября 2019

У меня есть входная матрица 4x4, и я хочу умножить каждый срез 2x2 на вес, сохраненный в матрице весов 3x3. Пожалуйста, см. Прилагаемое изображение для примера:

enter image description here

На изображении цветная секция входной матрицы 4x4 умножается на ту же цветную секциювесовая матрица 3х3 и сохраняется в выходной матрице 4х4. Когда срезы перекрываются, выходные данные получают сумму перекрытий (например, синий + красный).

Я пытаюсь выполнить эту операцию в Tensorflow 2.0, используя активные тензоры (которые можно рассматривать как массивы с нулевыми значениями). Это то, что я написал для выполнения этой операции, и она дает ожидаемый результат.

inputm = np.ones([4,4]) # initialize 4x4 input matrix
weightm = np.ones([3,3]) # initialize 3x3 weight matrix
outputm = np.zeros([4,4]) # initialize blank 4x4 output matrix

# iterate through each weight
for i in range(weightm.shape[0]):
    for j in range(weightm.shape[1]):
        outputm[i:i+2, j:j+2] += weightm[i,j] * inputm[i:i+2, j:j+2]

Однако я не думаю, что это эффективно, так как я перебираю весовую матрицу один за другим, и это будет очень медленно, когда мне нужно будет выполнить это на больших матрицах 500x500. Мне трудно определить способ векторизации этой операции, возможно, наложить матрицу весов так, чтобы она соответствовала форме входной матрицы, и выполнить умножение одной матрицы. Я также думал о выравнивании матрицы, но я все еще не могу найти способ сделать это более эффективно.

Любой совет будет высоко ценится. Заранее спасибо!

1 Ответ

1 голос
/ 11 ноября 2019

Хорошо, я думаю, что у меня есть решение, но оно включает в себя использование как простых операций (например, np.repeat), так и операций TensorFlow 2.0 (например, tf.segment_sum). И, чтобы предупредить вас, это не самое ясное элегантное решение в мире, но оно было самым элегантным, которое я мог придумать. Итак, вот так.

Главный виновник в вашей проблеме - это весовая матрица. Если вы манипулируете этой весовой матрицей, чтобы она была матрицей 4х4 (с правильной суммой весов в каждой позиции), у вас есть хорошая весовая матрица, которую вы можете выполнять поэлементным умножением с помощью входных данных. И это мое решение. Обратите внимание, что это разработано для проблемы 4x4, и вы сможете относительно легко расширить ее до матрицы 500x500.

import numpy as np
import tensorflow as tf

a = np.array([[1,2,3,4],[4,3,2,1],[1,2,3,4],[4,3,2,1]])
w = np.array([[5,4,3],[3,4,5],[5,4,3]])

# We make weights to a 6x6 matrix by repeating 2 times on both axis
w_rep = np.repeat(w,2,axis=0)
w_rep = np.repeat(w_rep,2,axis=1)

# Let's now jump in to tensorflow
tf_a = tf.constant(a)
tf_w = tf.constant(w_rep)
tf_segments = tf.constant([0,1,1,2,2,3])

# This is the most tricky bit, here we use the segment_sum to achieve what we need
# You can use segment_sum to get the sum of segments on the very first dimension of a matrix.
# So you need to do that to the input matrix twice. One on the original and the other on the transpose.

tf_w2 = tf.math.segment_sum(tf_w, tf_segments)
tf_w2 = tf.transpose(tf_w2)
tf_w2 = tf.math.segment_sum(tf_w2, tf_segments)
tf_w2 = tf.transpose(tf_w2)

print(tf_w2*a)

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

...