Achsen nach Index in Tensorflow eingeben

Sep 02 2020

Ich habe einen 3D-Tensor von Eingaben [batch, n_classes - k, 5]und einen 2D-Tensor von Indizes [batch, n_classes - k]. ksein kann [0, n_classes)als Beispiel nehmen n_classes=3, k=1:

X = tf.constant([
    [[0.36636186, 0.45606998, 0.785176  , 0.19967379, 0. ],
     [0.2799339 , 0.9548653 , 0.7378969 , 0.5543541 , 1. ]],

    [[0.07455064, 0.9868869 , 0.77224475, 0.19871569, 0. ],
     [0.19579114, 0.0693613 , 0.100778  , 0.01822183, 1. ]],

    [[0.684233  , 0.4401525 , 0.12203824, 0.4951769 , 0. ],
     [0.47417384, 0.09783416, 0.49161586, 0.47347176, 0. ]]
])

idcs = tf.constant([
    [0, 2],
    [0, 1],
    [1, 2]
])

Wobei Elemente in idcsKlassenwerte (Indizes) sind. Ich versuche, Xentlang der Achse 1 fehlende Indizes im Bereich zu unterstellen, indem ich (0, n_classes)sie auf Vektoren von Nullen setze, dh

tf.constant([
    [[0.36636186, 0.45606998, 0.785176  , 0.19967379, 0. ],
     [0.        , 0.        , 0.        , 0.        , 0. ],  # missing 1 in `idcs`
     [0.2799339 , 0.9548653 , 0.7378969 , 0.5543541 , 1. ]],

    [[0.07455064, 0.9868869 , 0.77224475, 0.19871569, 0. ],
     [0.19579114, 0.0693613 , 0.100778  , 0.01822183, 1. ],
     [0.        , 0.        , 0.        , 0.        , 0. ]], # missing 2 in `idcs`

    [[0.        , 0.        , 0.        , 0.        , 0. ],  # missing 0 in `idcs`
     [0.684233  , 0.4401525 , 0.12203824, 0.4951769 , 0. ],
     [0.47417384, 0.09783416, 0.49161586, 0.47347176, 0. ]]
])

Ich bin mir nicht ganz sicher, wie ich das im Tensorflow ausdrücken soll. Ich habe überlegt, einen Tensor aus Nullen zu erstellen [batch, n_classes, 5]und aktuelle Indizes Xentlang der Achse 1 zuzuweisen, aber die Zuordnung ist in Tensoren nicht zulässig. Gibt es eine einfache Möglichkeit, dies im Tensorflow zu erreichen?

Wenn ich dies zum Beispiel in Numpy ausdrücken würde, könnte ich etwas versuchen wie:

X = np.array([
    [[0.36636186, 0.45606998, 0.785176  , 0.19967379, 0. ],
     [0.2799339 , 0.9548653 , 0.7378969 , 0.5543541 , 1. ]],

    [[0.07455064, 0.9868869 , 0.77224475, 0.19871569, 0. ],
     [0.19579114, 0.0693613 , 0.100778  , 0.01822183, 1. ]],

    [[0.684233  , 0.4401525 , 0.12203824, 0.4951769 , 0. ],
     [0.47417384, 0.09783416, 0.49161586, 0.47347176, 0. ]]
])

idcs = np.array([
    [0, 2],
    [0, 1],
    [1, 2]
])

n_classes = 3
batch_size = 3

# selectors
x = np.repeat(np.arange(idcs.shape[0]), 2)  # [0, 0, 1, 1, 2, 2]
y = idcs.ravel()  # [0, 2, 0, 1, 1, 2]

z = np.zeros((batch_size, n_classes, 5))
z[x, y] = np.reshape(X, [x.shape[0], 5])
z

# array([[[0.36636186, 0.45606998, 0.785176  , 0.19967379, 0.        ],
#         [0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.2799339 , 0.9548653 , 0.7378969 , 0.5543541 , 1.        ]],
# 
#        [[0.07455064, 0.9868869 , 0.77224475, 0.19871569, 0.        ],
#         [0.19579114, 0.0693613 , 0.100778  , 0.01822183, 1.        ],
#         [0.        , 0.        , 0.        , 0.        , 0.        ]],
# 
#        [[0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.684233  , 0.4401525 , 0.12203824, 0.4951769 , 0.        ],
#         [0.47417384, 0.09783416, 0.49161586, 0.47347176, 0.        ]]])

Antworten

2 Tgsmith61591 Sep 02 2020 at 03:45

Ich löste dies mit einem kleinen Hack, indem ich den Tensor in spärlich und dann sofort wieder in dicht umwandelte:

batch_size, n_inputs, _ = X.shape.as_list()
n_classes = 3

sparse_indices = tf.concat([
        tf.reshape(tf.repeat(tf.range(batch_size, dtype=tf.int64), n_inputs * 5), [-1, 1]),
        tf.reshape(tf.repeat(idcs, 5), [-1, 1]),
        tf.reshape(tf.tile(tf.range(5, dtype=tf.int64), [n_inputs * batch_size]), [-1, 1]),
    ],
    axis=1
)

# ravel X to 1d, create a sparse tensor for non-zero indices and then
# expand back to dense as a hack for filling in the zeros
X_ravel = tf.reshape(X, shape=[-1])
tf.sparse.to_dense(
    tf.sparse.SparseTensor(
        sparse_indices,
        X_ravel,
        dense_shape=[batch_size, n_classes, 5],
    ),
)

Was wie erwartet ergibt:

<tf.Tensor: shape=(3, 3, 5), dtype=float32, numpy=
array([[[0.36636186, 0.45606998, 0.785176  , 0.19967379, 0.        ],
        [0.        , 0.        , 0.        , 0.        , 0.        ],
        [0.2799339 , 0.9548653 , 0.7378969 , 0.5543541 , 1.        ]],

       [[0.07455064, 0.9868869 , 0.77224475, 0.19871569, 0.        ],
        [0.19579114, 0.0693613 , 0.100778  , 0.01822183, 1.        ],
        [0.        , 0.        , 0.        , 0.        , 0.        ]],

       [[0.        , 0.        , 0.        , 0.        , 0.        ],
        [0.47417384, 0.09783416, 0.49161586, 0.47347176, 0.        ],
        [0.684233  , 0.4401525 , 0.12203824, 0.4951769 , 0.        ]]],
      dtype=float32)>