Подача.npy (файлы numpy) в конвейер данных тензорного потока
Tensorflow, похоже, не хватает ридера для файлов.npy. Как я могу прочитать мои файлы данных в новом трубопроводе tenorflow.data.Dataset? Мои данные не помещаются в памяти.
Каждый объект сохраняется в отдельном файле.npy. каждый файл содержит 2 разных ndarrays как функции и скаляр как их метку.
4 ответа
Вписываются ли ваши данные в память? Если это так, вы можете следовать инструкциям из раздела " Использование NumPy Arrays " в документации:
Использование массивов NumPy
Если все ваши входные данные помещаются в память, самый простой способ создать из них набор данных - это преобразовать их в объекты tf.Tensor и использовать Dataset.from_tensor_slices().
# Load the training data into two NumPy arrays, for example using `np.load()`.
with np.load("/var/data/training_data.npy") as data:
features = data["features"]
labels = data["labels"]
# Assume that each row of `features` corresponds to the same row as `labels`.
assert features.shape[0] == labels.shape[0]
dataset = tf.data.Dataset.from_tensor_slices((features, labels))
В случае, если файл не помещается в память, кажется, что единственный рекомендуемый подход - сначала преобразовать npy
данные в TFRecord
формат, а затем используйте TFRecord
формат набора данных, который можно передавать без полной загрузки в память.
Вот пост с некоторыми инструкциями.
FWIW, мне кажется сумасшедшим, что TFRecord
не может быть создан непосредственно с именем каталога или именами файлов npy, но, похоже, это ограничение простого Tensorflow.
Если вы можете разбить один большой файл npy на более мелкие файлы, каждый из которых приблизительно представляет один пакет для обучения, то вы можете написать собственный генератор данных в Keras, который будет выдавать только данные, необходимые для текущего пакета.
В общем случае, если ваш набор данных не помещается в памяти, его хранение в виде одного большого файла npy усложняет работу, и желательно сначала переформатировать данные, либо как TFRecord, либо как несколько файлов npy, а затем использовать другие методы.,
На самом деле можно читать напрямую файлы NPY с помощью TensorFlow вместо TFRecords. Ключевые части tf.data.FixedLengthRecordDataset
а также tf.decode_raw
вместе с просмотром документации по формату NPY. Для простоты предположим, что файл NPY float32, содержащий массив с формой (N, K)
дается, и вы знаете количество функций K
заранее, а также тот факт, что это массив float32. Файл NPY - это просто двоичный файл с небольшим заголовком, за которым следуют необработанные данные массива (объектные массивы отличаются, но мы сейчас рассматриваем числа). Короче говоря, вы можете найти размер этого заголовка с помощью такой функции:
def npy_header_offset(npy_path):
with open(str(npy_path), 'rb') as f:
if f.read(6) != b'\x93NUMPY':
raise ValueError('Invalid NPY file.')
version_major, version_minor = f.read(2)
if version_major == 1:
header_len_size = 2
elif version_major == 2:
header_len_size = 4
else:
raise ValueError('Unknown NPY file version {}.{}.'.format(version_major, version_minor))
header_len = sum(b << (8 * i) for i, b in enumerate(f.read(header_len_size)))
header = f.read(header_len)
if not header.endswith(b'\n'):
raise ValueError('Invalid NPY file.')
return f.tell()
С этим вы можете создать набор данных следующим образом:
import tensorflow as tf
npy_file = 'my_file.npy'
num_features = ...
dtype = tf.float32
header_offset = npy_header_offset(npy_file)
dataset = tf.data.FixedLengthRecordDataset([npy_file], num_features * dtype.size, header_bytes=header_offset)
Каждый элемент этого набора данных содержит длинную строку байтов, представляющих один пример. Теперь вы можете декодировать его, чтобы получить реальный массив:
dataset = dataset.map(lambda s: tf.decode_raw(s, dtype))
Элементы будут иметь неопределенную форму, потому что TensorFlow не отслеживает длину строк. Вы можете просто применить форму, так как вы знаете количество функций:
dataset = dataset.map(lambda s: tf.reshape(tf.decode_raw(s, dtype), (num_features,)))
Точно так же вы можете выполнить этот шаг после пакетирования или комбинировать его так, как вам хочется.
Ограничение заключается в том, что вам нужно было заранее знать количество функций. Тем не менее, его можно извлечь из заголовка NumPy, немного мучительно, и в любом случае очень трудно изнутри TensorFlow, поэтому имена файлов должны быть известны заранее. Другое ограничение заключается в том, что решение само по себе требует, чтобы вы использовали либо один файл на набор данных, либо файлы с одинаковым размером заголовка, хотя, если вы знаете, что все массивы имеют одинаковый размер, это должно быть на самом деле.
Следует признать, что если принять во внимание такой подход, может быть лучше иметь чистый двоичный файл без заголовков и либо жестко закодировать количество функций, либо прочитать их из другого источника...
Вы можете сделать это с помощью tf.py_func, см. Пример здесь. Функция разбора просто расшифровывает имя файла из байтов в строку и вызывает np.load.
Обновление: как то так:
def read_npy_file(item):
data = np.load(item.decode())
return data.astype(np.float32)
file_list = ['/foo/bar.npy', '/foo/baz.npy']
dataset = tf.data.Dataset.from_tensor_slices(file_list)
dataset = dataset.map(
lambda item: tuple(tf.py_func(read_npy_file, [item], [tf.float32,])))
Настройка проблемы
У меня была папка с изображениями, которые загружались в модель InceptionV3 для извлечения функций. Это казалось огромным узким местом для всего процесса. В качестве обходного пути я извлек элементы из каждого изображения, а затем сохранил их на диске в формате.
Теперь у меня было две папки, одна для изображений и одна для соответствующих файлов. Возникла очевидная проблема с загрузкой файлов в конвейер.
Обходной путь
Я наткнулся на официальное руководство TensorFlow по посещению выставок и рассказал, у которого было отличное решение проблемы, с которой столкнулась эта ветка (и я).
Загрузить nummpy файлов
Прежде всего, нам нужно создать функцию сопоставления, которая принимает имя файла и возвращает массив numpy.
# Load the numpy files
def map_func(feature_path):
feature = np.load(feature_path)
return feature
Использовать
С <tcode id="47455372"></tcode>мы можем обернуть любую функцию Python и использовать ее как операцию TensorFlow. Функция должна принимать numpy-объект (это именно то, что мы хотим).
Создаем список со списком всех
.npy
имена файлов.
dataset = tf.data.Dataset.from_tensor_slices(feature_paths)
Затем мы используем
map
функция
tf.data.Dataset
API для выполнения остальной части нашей задачи.
# Use map to load the numpy files in parallel
dataset = dataset.map(lambda item: tf.numpy_function(
map_func, [item], tf.float16),
num_parallel_calls=tf.data.AUTOTUNE)