Tensorflow semble ne pas disposer d’un lecteur pour les fichiers ".npy" . Comment puis-je lire mes fichiers de données dans la nouvelle page Tensorflow.data.Dataset? Mes données ne tiennent pas dans la mémoire.
Chaque objet est enregistré dans un fichier ".npy" séparé. chaque fichier contient 2 ndarrays différents en tant qu'entités et un scalaire en tant qu'étiquette.
Vos données entrent-elles dans la mémoire? Si tel est le cas, vous pouvez suivre les instructions de la section Consomming NumPy Arrays de la documentation:
Consommer des tableaux NumPy
Si toutes vos données d'entrée tiennent dans la mémoire, le moyen le plus simple de créer un jeu de données à partir d'eux est de les convertir en objets tf.Tensor et d'utiliser 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))
Dans le cas où le fichier ne rentre pas dans la mémoire, il semble que la seule approche recommandée consiste à convertir d'abord les données npy
en un format TFRecord
, puis à utiliser le format de jeu de données TFRecord
, qui peut être transféré sans chargement complet dans la mémoire. .
Voici un post avec quelques instructions.
FWIW, il me semble fou que TFRecord
ne puisse pas être instancié avec un nom de répertoire ou un nom de fichier de fichiers npy directement, mais cela semble être une limitation de Tensorflow brut.
Si vous pouvez fractionner le fichier npy unique en gros en fichiers plus petits représentant chacun un lot de formation, vous pouvez écrire un générateur de données personnalisé dans Keras qui ne produira que les données nécessaires au lot en cours.
En général, si votre jeu de données ne peut pas tenir dans la mémoire, le stocker dans un seul fichier volumineux rend le travail très difficile. De préférence, reformatez les données en premier, sous forme de fichier TFRecord ou de plusieurs fichiers npy, puis utilisez d'autres méthodes. .
Vous pouvez le faire avec tf.py_func, voir l'exemple here . La fonction d'analyse décodera simplement le nom de fichier d'octets en chaîne et appellera np.load.
Mise à jour: quelque chose comme ça:
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,])))
Il est effectivement possible de lire directement des fichiers NPY avec TensorFlow au lieu de TFRecords. Les éléments clés sont tf.data.FixedLengthRecordDataset
et tf.decode_raw
, ainsi qu’un aperçu de la documentation du format NPY . Pour simplifier, supposons qu'un fichier NPY float32 contenant un tableau de forme (N, K)
soit fourni et que vous connaissiez auparavant le nombre d'entités K
, ainsi que le fait qu'il s'agisse d'un tableau float32. Un fichier NPY est simplement un fichier binaire avec un petit en-tête et suivi des données de tableau brutes (les tableaux d'objets sont différents, mais nous envisageons des nombres maintenant). En bref, vous pouvez trouver la taille de cet en-tête avec une fonction comme celle-ci:
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()
Avec cela, vous pouvez créer un jeu de données comme ceci:
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)
Chaque élément de cet ensemble de données contient une longue chaîne d'octets représentant un seul exemple. Vous pouvez maintenant le décoder pour obtenir un tableau réel:
dataset = dataset.map(lambda s: tf.decode_raw(s, dtype))
Les éléments auront une forme indéterminée, cependant, car TensorFlow ne garde pas trace de la longueur des chaînes. Vous pouvez simplement appliquer la forme puisque vous connaissez le nombre de fonctionnalités:
dataset = dataset.map(lambda s: tf.reshape(tf.decode_raw(s, dtype), (num_features,)))
De même, vous pouvez choisir d'effectuer cette étape après la mise en lot ou de la combiner à votre guise.
La limitation est que vous deviez connaître le nombre de fonctionnalités à l'avance. Il est possible de l'extraire de l'en-tête NumPy, bien que cela soit un peu pénible et, en tout état de cause, très difficilement de TensorFlow, de sorte que les noms de fichiers doivent être connus à l'avance. Une autre limitation est que, dans l'état actuel des choses, la solution vous oblige à n'utiliser qu'un fichier par ensemble de données ou des fichiers ayant la même taille d'en-tête, bien que vous sachiez que tous les tableaux ont la même taille, ce qui devrait être le cas.
Certes, si l’on considère ce type d’approche, il serait peut-être préférable d’avoir un fichier binaire pur sans en-têtes, et de coder en dur le nombre de fonctionnalités ou de les lire depuis une source différente ...