Этот вопрос является продолжением двух предыдущих вопросов:
Для контекста эти два предыдущих вопроса охватывают обработку pre шаг, т.е. преобразование ваших данных в соответствие с примером Tensorflow (Sequence) (tf.train.Example
/ tf.train.SequenceExample
), чтобы вы могли использовать формат записи Tensorflow.Кроме того, они относятся к этапу «восстановления», т. Е. Учитывая, что ваши данные теперь являются Tensorflow Record, как их преобразовать в tf.data.Dataset
.Есть также два связанных колба (1
, 2
).
Этот вопрос относится к шагам 3/4 или предварительной обработке (см. Схему ниже).для справки).Знание предыдущих шагов может быть уместным.
data pipeline
(1) raw data
|
|
| (pre-pre-preprocessing: raw data to cleaned data)
|
v
(2) cleaned data
|
|
| (pre-preprocessing: cleaned data into (Sequence)Example / Record)
|
v
(3) tf.Record (<-- tf docs tend to believe that your data starts here)
|
|
| (recovery: tf.data.TFRecordDataset(filenames).map(lambda r: parse(r)))
|
v
(4) tf.data.Dataset
|
|
| (preprocessing: dataset.map() etc into final (features, labels) form
|
v
(5) data iterator
|
|
|
|
|
v
(6) train
Итак, теперь мы разбросали наши данные по нескольким файлам записей:
n_shards = 10
tf_record_files = ['shard_{}.record'.format(i) for i in range(n_shards)]
и создали набор данных тензорного потока:
ds = tf.data.TFRecordDataset(tf_record_files)
первое, что нужно сделать, - это проанализировать наш (Sequence) пример Protos («записи»)
context_features = {
# whatever you data is
}
sequence_features = None # or whatever your sequence features are
def parse_fn(record, ctx_fts, seq_fts=None):
p = tf.parse_single_example if seq_fts is None else tf.parse_single_sequence_example
return p(record, context_features=ctx_fts, sequence_features=seq_fts)
ds = ds.map(lambda r: parse_fn(r, context_features, sequence_features))
или при использовании сторонней библиотеки, такой как fio :
from fio import FIO
schema = {
# data structure
}
fio = FIO(schema)
ds = ds.map(lambda r: fio.from_record(r))
предположим, что для одного примера у нас есть что-то вроде:
# example
{
'a': 10,
'b': 20,
'c': 'e1'
}
, тогда (при условии ds.batch(1)
) наш пример на данный момент:
{
'a': <tf.Tensor 'ParseSingleExample/ParseSingleExample:0' shape=() dtype=int64>,
'b': <tf.Tensor 'ParseSingleExample/ParseSingleExample:1' shape=() dtype=int64>,
'c': <tf.Tensor 'ParseSingleExample/ParseSingleExample:2' shape=() dtype=string>
}
и работает sess.eval
:
{
'a': array([10]),
'b': array([20],
'c': array([b'e1']
}
Это примечательно как 1. данные являются типами TF и должны обрабатываться как таковые; 2. строки двоично кодируются (даже после eval).
У меня есть функция python, которая упаковывает системную команду, которая преобразует строку tsv
# e.g. something like this
labels = convert_tsv_to_labels(tsv_string)
, где tsv_string
будет выглядеть примерно так:
"""
10\t20\e1\n # <--- example 1
20\t15\e2\n
"""
какэта функция 1. Python (хотя она вызывает os.subprocess
) 2. Нетривиально, было бы неплохо использовать это вшаг предварительной обработки.Кроме того, этикетки могут меняться в зависимости от эпохи.Таким образом, мой вопрос заключается в том, как сделать это в точке конвейера преобразования данных.Предварительный расчет и хранение всех меток является чрезмерным.
Тем не менее, в этот момент атрибуты разбиваются на массивы TF.Итак, как бы я поступил об этом?
Например,
def transform_fn(record):
tsv_str = record_to_tsv
record['label'] = convert_tsv_to_labels(tsv_str)
return record
ds.map(lambda r: transform_fn(r))
Примечание: эта функция может обрабатывать несколько строк одновременно