Tensorflow 2.0: масштабирование всех элементов из TFRecordDataset перед обработкой - PullRequest
0 голосов
/ 13 марта 2020

При записи набора данных TFRecord я также сохранил sklearn StandardScaler с параметрами масштабирования для набора данных. Данные, однако, не были масштабированы. Я хочу масштабировать его в момент чтения, используя функцию tf.data.Dataset.map, и, хотя я действительно нашел способ сделать это, в настоящее время он выглядит немного громоздким, требуя двух вызовов функции переноса для его работы. Я опубликую пример моего подхода на некоторых фиктивных данных, имитирующих случай записи / чтения:


from sklearn.preprocessing import StandardScaler
import tensorflow as tf

# dummy data
data = np.array([[7, 5, 9], [1, 0, 8], [2, 6, 3,], [2, 3, 6]], dtype=np.float32)
label = np.array([[1], [0], [0], [1]], dtype=np.int32)

# fitting the scale. I use partial fit to simulate the way
# scl will be fit when writing the TFRecordDataset
for row in data:
    scl.partial_fit(row.reshape(1, -1))
    # *** WRITE EACH ROW TO TFRECORD HERE *** #

# Scale the data
data_s = scl.transform(data)

# Create the tf.data.Dataset. This line simulates reading the TFRecords
# in a TFRecordDataset, and parsing it in a Dataset
dataset = tf.data.Dataset.from_tensor_slices((data, label))

# Scaler function. This is the function called by eager execution
def myscale(segment, label):
    return scl.transform(segment.numpy().reshape(1, -1)).reshape(-1), label

# Mapping the scaler function. Here is my point of contention!
mdataset = dataset.map(lambda x, y: tf.py_function(scale, [x, y], (x.dtype, y.dtype)))

# Let's check the outputs:
print('Dataset (only data)')
for element in dataset:
    print(element[0], '--', element[1])

print('\nafter scale (only data)')
for element in mdataset:
    print(element[0], '--', element[1])

print('\nsklearn scaler.transform output')
print(data_s)

Вывод на печать:

Dataset
tf.Tensor([7. 5. 9.], shape=(3,), dtype=float32) -- tf.Tensor([1], shape=(1,), dtype=int32)
tf.Tensor([1. 0. 8.], shape=(3,), dtype=float32) -- tf.Tensor([0], shape=(1,), dtype=int32)
tf.Tensor([2. 6. 3.], shape=(3,), dtype=float32) -- tf.Tensor([0], shape=(1,), dtype=int32)
tf.Tensor([2. 3. 6.], shape=(3,), dtype=float32) -- tf.Tensor([1], shape=(1,), dtype=int32)

After scale
tf.Tensor([1.7056057  0.65465367 1.0910895 ], shape=(3,), dtype=float32) -- tf.Tensor([1], shape=(1,), dtype=int32)
tf.Tensor([-0.8528029  -1.5275252   0.65465367], shape=(3,), dtype=float32) -- tf.Tensor([0], shape=(1,), dtype=int32)
tf.Tensor([-0.42640144  1.0910895  -1.5275252 ], shape=(3,), dtype=float32) -- tf.Tensor([0], shape=(1,), dtype=int32)
tf.Tensor([-0.42640144 -0.2182179  -0.2182179 ], shape=(3,), dtype=float32) -- tf.Tensor([1], shape=(1,), dtype=int32)

sklearn scaler.transform output
[[ 1.7056057   0.65465367  1.0910895 ]
 [-0.8528029  -1.5275252   0.65465367]
 [-0.42640144  1.0910895  -1.5275252 ]
 [-0.42640144 -0.2182179  -0.2182179 ]]

Как видите, он работает просто хорошо. Но моя маленькая любимая мозоль - это то, как мне нужно дважды обернуть функцию scaler.transform: одну с привязанной лямбда-функцией, а другую с функцией myscale внутри py_function, чтобы я мог использовать активное выполнение Tensorflow и доступ numpy массив моих тензоров для применения scaler.transform.

Итак, мой вопрос: есть ли более простой способ сделать это?

РЕДАКТИРОВАТЬ: я только что заметил еще одну потенциальную проблему с этим решением. Если по какой-либо причине scl выходит за рамки функции myscaler, это решение будет нарушено. Поскольку я могу отправлять только тензоры в качестве входных данных для py_function, я не уверен, что для этого есть простое решение.

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