Je suis nouveau sur tensorflow, mais j'ai déjà suivi et exécuté les didacticiels qu'ils promeuvent et bien d'autres sur le Web. J'ai créé un petit réseau neuronal convolutif sur les images du MNIST. Rien de spécial, mais je voudrais tester sur mes propres images. Maintenant, mon problème vient: j'ai créé plusieurs dossiers; le nom de chaque dossier est la classe (étiquette) à laquelle appartiennent les images à l'intérieur.
Les images ont différentes formes; je veux dire qu'ils n'ont pas de taille fixe.
Comment puis-je les charger pour les utiliser avec Tensorflow?
J'ai suivi de nombreux tutoriels et réponses ici sur StackOverflow et sur d'autres sites Q/A. Mais quand même, je n'ai pas compris comment faire ça.
L'API tf.data
(Tensorflow 1.4 à partir de) est idéal pour des choses comme ça. Le pipeline ressemblera à ceci:
tf.data.Dataset
Initial qui itère sur tous les exemplesshuffle
/repeat
l'ensemble de données;map
grâce à une fonction qui rend toutes les images de la même taille;batch
;prefetch
pour dire à votre programme de pré-traiter les lots de données suivants pendant que le réseau traite le lot en cours; etIl existe plusieurs façons de créer votre jeu de données initial (voir ici pour une réponse plus approfondie)
Prenant en charge la version 1.12 de tensorflow, ensembles de données Tensorflow fournit une API relativement simple pour créer des ensembles de données tfrecord, et gère également le téléchargement de données, le partage, la génération de statistiques et d'autres fonctionnalités automatiquement.
Voir par ex. cette implémentation de l'ensemble de données de classification d'image . Il y a beaucoup de choses dans la comptabilité (URL de téléchargement, citations, etc.), mais la partie technique se résume à spécifier features
et à écrire une fonction _generate_examples
features = tfds.features.FeaturesDict({
"image": tfds.features.Image(shape=(_TILES_SIZE,) * 2 + (3,)),
"label": tfds.features.ClassLabel(
names=_CLASS_NAMES),
"filename": tfds.features.Text(),
})
...
def _generate_examples(self, root_dir):
root_dir = os.path.join(root_dir, _TILES_SUBDIR)
for i, class_name in enumerate(_CLASS_NAMES):
class_dir = os.path.join(root_dir, _class_subdir(i, class_name))
fns = tf.io.gfile.listdir(class_dir)
for fn in sorted(fns):
image = _load_tif(os.path.join(class_dir, fn))
yield {
"image": image,
"label": class_name,
"filename": fn,
}
Vous pouvez également générer le tfrecords
à l'aide d'opérations de niveau inférieur.
tf.data.Dataset.map
Et tf.py_func(tion)
Vous pouvez également charger les fichiers image à partir des noms de fichiers dans tf.data.Dataset.map
Comme ci-dessous.
image_paths, labels = load_base_data(...)
Epoch_size = len(image_paths)
image_paths = tf.convert_to_tensor(image_paths, dtype=tf.string)
labels = tf.convert_to_tensor(labels)
dataset = tf.data.Dataset.from_tensor_slices((image_paths, labels))
if mode == 'train':
dataset = dataset.repeat().shuffle(Epoch_size)
def map_fn(path, label):
# path/label represent values for a single example
image = tf.image.decode_jpeg(tf.read_file(path))
# some mapping to constant size - be careful with distorting aspec ratios
image = tf.image.resize_images(out_shape)
# color normalization - just an example
image = tf.to_float(image) * (2. / 255) - 1
return image, label
# num_parallel_calls > 1 induces intra-batch shuffling
dataset = dataset.map(map_fn, num_parallel_calls=8)
dataset = dataset.batch(batch_size)
# try one of the following
dataset = dataset.prefetch(1)
# dataset = dataset.apply(
# tf.contrib.data.prefetch_to_device('/gpu:0'))
images, labels = dataset.make_one_shot_iterator().get_next()
Je n'ai jamais travaillé dans un environnement distribué, mais je n'ai jamais remarqué de baisse de performances en utilisant cette approche sur tfrecords
. Si vous avez besoin de plus de fonctions de chargement personnalisées, consultez également tf.py_func
.
Informations plus générales ici , et notes sur les performances ici
Exemple de script de pipeline d'entrée pour charger des images et des étiquettes à partir du répertoire. Vous pouvez effectuer un prétraitement (redimensionnement des images, etc.) après cela.
import tensorflow as tf
filename_queue = tf.train.string_input_producer(
tf.train.match_filenames_once("/home/xxx/Desktop/stackoverflow/images/*/*.png"))
image_reader = tf.WholeFileReader()
key, image_file = image_reader.read(filename_queue)
S = tf.string_split([key],'/')
length = tf.cast(S.dense_shape[1],tf.int32)
# adjust constant value corresponding to your paths if you face issues. It should work for above format.
label = S.values[length-tf.constant(2,dtype=tf.int32)]
label = tf.string_to_number(label,out_type=tf.int32)
image = tf.image.decode_png(image_file)
# Start a new session to show example output.
with tf.Session() as sess:
# Required to get the filename matching to run.
tf.initialize_all_variables().run()
# Coordinate the loading of image files.
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
for i in xrange(6):
# Get an image tensor and print its value.
key_val,label_val,image_tensor = sess.run([key,label,image])
print(image_tensor.shape)
print(key_val)
print(label_val)
# Finish off the filename queue coordinator.
coord.request_stop()
coord.join(threads)
Répertoire de fichiers
./images/1/1.png
./images/1/2.png
./images/3/1.png
./images/3/2.png
./images/2/1.png
./images/2/2.png
Production:
(881, 2079, 3)
/home/xxxx/Desktop/stackoverflow/images/3/1.png
3
(155, 2552, 3)
/home/xxxx/Desktop/stackoverflow/images/2/1.png
2
(562, 1978, 3)
/home/xxxx/Desktop/stackoverflow/images/3/2.png
3
(291, 2558, 3)
/home/xxxx/Desktop/stackoverflow/images/1/1.png
1
(157, 2554, 3)
/home/xxxx/Desktop/stackoverflow/images/1/2.png
1
(866, 936, 3)
/home/xxxx/Desktop/stackoverflow/images/2/2.png
2