Могу ли я получить местоположение каждого столбца функций после объединения в плотном слое тензорного потока keras - PullRequest
0 голосов
/ 14 июля 2020

Существует ли API с керасом тензорного потока для определения того, где функции оказываются в плотном слое? То есть, учитывая список столбцов функций, скажем

cols = [numeric_feature, bucketized_feature, embedded_categorical_feature]

, и если вы затем создадите слой функций

    feature_layer = tf.keras.layers.DenseFeatures(cols)

, как вы можете определить, какой столбец numeric_feature занимает в feature_layer? Аналогично, если bucketized_feature - это 3 ведра, где эти 3 столбца? numeri c и с разделением на две части, а также размер встраивания - из-за его использования в коде это кажется «официальным» способом определения ширины объекта в плотном слое, но я не видел API чтобы указать порядок функций - я думал, что это будет их порядок в аргументе cols для DenseLayer, но мой тест показывает, что это не так, порядок embedded_categorical, numeric, bucketized, когда Я даю numeric bucketized, а затем категоричный в конце.

Было бы неплохо иметь возможность идентифицировать расположение пространственных объектов в плотном слое - но, возможно, это не определено каким-то образом пользователь может положиться на?

Ниже приведен модульный тест, который не прошел, потому что я предполагал, что заказ был для списка cols

import unittest
import numpy as np
import tensorflow as tf
from tensorflow import feature_column


def where_feats_in_concat_state(state_columns):
    locs = {}
    next_loc = 0
    for feature_column in state_columns:
        width = feature_column.variable_shape.num_elements()
        locs[feature_column.name] = {"start": next_loc, "width": width}
        next_loc += width
    return locs


class WhereFeatsInConcatState(unittest.TestCase):
    def test_basic(self):
        N = 10
        vocab_N = 20
        bsize = 1
        vocab = list(map(str, np.arange(vocab_N)))
        data = {'numeric1': np.random.randn(N, 1).astype(np.float32),
                'numeric2': np.random.randn(N, 1).astype(np.float32),
                'categorical1': np.reshape(np.array(list(map(str, np.random.randint(0, vocab_N-1, N)))), [N, 1]),
                'categorical2': np.reshape(np.array(list(map(str, np.random.randint(0, vocab_N, N)))), [N, 1])}
        numeric1 = feature_column.numeric_column("numeric1")
        numeric2 = feature_column.numeric_column("numeric2")
        bins = [-2, -1, -0.5, -0.1, .1, 0.5, 1, 2]
        bucket1 = feature_column.bucketized_column(numeric2, boundaries=bins)
        cat1 = feature_column.categorical_column_with_vocabulary_list('categorical1', vocab)
        cat2 = feature_column.categorical_column_with_vocabulary_list('categorical2', vocab)
        emb1 = feature_column.embedding_column(cat1, dimension=4)
        emb2 = feature_column.embedding_column(cat2, dimension=3)
        state_columns = [numeric1, bucket1, emb1, emb2]
        locs = where_feats_in_concat_state(state_columns=state_columns)
        numeric1_start, numeric1_width = locs['numeric1']['start'], locs['numeric1']['width']
        bucket1_start, bucket1_width = locs['numeric2_bucketized']['start'], locs['numeric2_bucketized']['width']
        emb1_start, emb1_width = locs['categorical1_embedding']['start'], locs['categorical1_embedding']['width']
        emb2_start, emb2_width = locs['categorical2_embedding']['start'], locs['categorical2_embedding']['width']
        state_width = emb2_start + emb2_width
        self.assertEqual(1, numeric1_width)

        feature_layer = tf.keras.layers.DenseFeatures(state_columns)
        ds = tf.data.Dataset.from_tensor_slices(data).batch(bsize)
        for idx, batch in enumerate(ds):
            state = feature_layer(batch).numpy()
            self.assertEqual(state_width, state.shape[1])
            numeric1_answser = data['numeric1'][idx, 0]
            numeric2_answser = data['numeric2'][idx, 0]
            bucket2_idx_answer = np.digitize(numeric2_answser, bins=bins, right=False)
            bucket2_onehot_answer = np.eye(1 + len(bins))[bucket2_idx_answer]

            where_res = state[0, numeric1_start]
            self.assertAlmostEqual(numeric1_answser, where_res,
                                   msg="idx=%d feat=numeric1\nanswer=%.3f col=%d\nres=%.3f\nstate=%s\nbucket2_one_hot=%s" %
                                       (idx, numeric1_answser, numeric1_start, where_res, state, bucket2_onehot_answer))

if __name__ == "__main__":
    unittest.main()

Последний запуск дал:

AssertionError: 1.178217 != 0.25312936 within 7 places (0.9250877 difference) : idx=0 feat=numeric1
answer=1.178 col=0
res=0.253
state=[[ 0.25312936  0.08003955 -0.01629014  0.23871408  0.3213957  -0.4140397
   0.51011735  1.178217    0.          0.          0.          0.
   0.          0.          1.          0.          0.        ]]
bucket2_one_hot=[0. 0. 0. 0. 0. 0. 1. 0. 0.]

, что показывает, что это вложения, numeri c, чем ведро.

...