Как разделить тензорные элементы на заданные c индексы - PullRequest
2 голосов
/ 28 апреля 2020

У меня есть такой тензор:

out = [[ 3,  6,  5,  4],
       [ 6,  5, 10, 13],
       [ 5, 10,  6, 22],
       [ 4, 13, 22,  9]]

И это симметричная матрица. Что я хочу сделать, это разделить каждый элемент на значения в тех же индексах по диагонали. Таким образом, значения диагонали в этой матрице:

index0 = 3
index1 = 5
index2 = 6
index3 = 9

Результат будет выглядеть так:

[[3      ,  6/(3*5) ,  5/(3*6) ,  4/(3*9) ]
 [6/(3*5),  5       ,  10/(5*6),  13/(5*9)]
 [5/(3*6),  10/(5*6),  6       ,  22/(6*9)]
 [4/(3*9),  13/(5*9),  22/(6*9),  9       ]]

Позвольте мне пройти через первый ряд:

3 - это значение в диагонали, поэтому мы пропустим его

6/3*5, 6 - это значение в index 0 and 1, так что я разделю 6 на диагональные значения в index0 and 1.

5/3*6, 5 - это значение по индексу 0 and 2, поэтому я разделю его на диагональные значения по индексу 0 and 2

4/3*9, 4 - это значение по индексу 0 and 3, чтобы я разделил его на диагональные значения по индексу 0 and 3

Ответы [ 3 ]

3 голосов
/ 28 апреля 2020

Это можно сделать следующим образом в тензорном потоке (или numpy).

  1. Мы берем исходную матрицу и обнуляем диагональ.
  2. Делим полученную матрицу на диагональ vector.
  3. Мы транспонируем результат из 2 и делим его снова по диагональному вектору.
  4. Добавляем диагональ, которую мы обнулили на шаге 1.
import tensorflow as tf

out = [[ 3,  6,  5,  4],
       [ 6,  5, 10, 13],
       [ 5, 10,  6, 22],
       [ 4, 13, 22,  9]]

tensor = tf.constant(out, dtype=tf.float32)

diag_indices = tf.tile(tf.range(tf.shape(tensor)[0])[..., None], [1, 2])
diag = tf.gather_nd(tensor, diag_indices) # [3. 5. 6. 9.]

diag_matrix = tf.linalg.tensor_diag(diag)
zero_diag_matrix = tensor - diag_matrix
res = tf.transpose(zero_diag_matrix / diag) / diag + diag_matrix

with tf.Session() as sess:
    print(res.eval())
# [[3.         0.4        0.27777776 0.14814815]
#  [0.4        5.         0.33333334 0.28888887]
#  [0.27777776 0.3333333  6.         0.4074074 ]
#  [0.14814815 0.28888887 0.4074074  9.        ]]

2 голосов
/ 28 апреля 2020

Используя numpy, вы можете сделать следующее:

import numpy as np

out = out.astype(float)
# diagonal elements in out
d = np.copy(np.diagonal(out))
# Indices of lower triangular matriX
tril_ix = np.tril_indices_from(out, k=-1)
# cumulative sum of the diagonal values
# over the first axis on a square matrix
dx = np.cumsum(np.diag(d), 1) 
# replicate ove lower triangular
dx[tril_ix] += np.rot90(dx, k=1)[::-1][tril_ix]
# same but accumulating the diagonal elements
# upwards on the y axis
dy = np.cumsum(np.diag(d)[::-1],0)[::-1]
# replicate ove rlower triangular
dy[tril_ix] += np.rot90(dy, k=1)[::-1][tril_ix]
# mask where to apply the product
m = dy!=0
# perform div and mult
out[m] = out[m]/(dx[m]*dy[m])
np.fill_diagonal(out, d)

print(out)

array([[3.        , 0.4       , 0.27777778, 0.14814815],
       [0.4       , 5.        , 0.33333333, 0.28888889],
       [0.27777778, 0.33333333, 6.        , 0.40740741],
       [0.14814815, 0.28888889, 0.40740741, 9.        ]])
1 голос
/ 28 апреля 2020

Вот версия с тензорным потоком.

import tensorflow as tf
import numpy as np

out = tf.Variable([[ 3,  6,  5,  4],
                   [ 6,  5, 10, 13],
                   [ 5, 10,  6, 22],
                   [ 4, 13, 22,  9]], dtype=tf.float32)

# this solution only works for square matrices
assert out.shape[-2] == out.shape[-1]

out_diag = tf.linalg.diag_part(out)
res = tf.Variable(tf.zeros(out.shape, dtype=tf.float32))

for i in tf.range(out.shape[0]):
    _ = res[..., (i+1):, i].assign(out[..., (i+1):, i] / out_diag[..., (i+1):] / out_diag[..., i])
    _ = res[..., i, (i+1):].assign(out[..., i, (i+1):] / out_diag[..., (i+1):] / out_diag[..., i])

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