Je construis un modèle de classification d'image standard avec Tensorflow. Pour cela, j'ai des images d'entrée, chacune avec une étiquette (numéro entre {0,1}). Les données peuvent donc être stockées dans une liste en utilisant le format suivant:
/path/to/image_0 label_0
/path/to/image_1 label_1
/path/to/image_2 label_2
...
Je souhaite utiliser le système de mise en file d'attente de TensorFlow pour lire mes données et les transmettre à mon modèle. En ignorant les étiquettes, on peut facilement y parvenir en utilisant string_input_producer
et wholeFileReader
. Voici le code:
def read_my_file_format(filename_queue):
reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)
example = tf.image.decode_png(value)
return example
#removing label, obtaining list containing /path/to/image_x
image_list = [line[:-2] for line in image_label_list]
input_queue = tf.train.string_input_producer(image_list)
input_images = read_my_file_format(input_queue)
Toutefois, les étiquettes sont perdues au cours de ce processus, car les données d'image sont délibérément mélangées dans le cadre du pipeline d'entrée. Quel est le moyen le plus simple de faire passer les étiquettes avec les données d'image dans les files d'attente?
En utilisant slice_input_producer
fournit une solution beaucoup plus propre. Slice Input Producer nous permet de créer une file d’entrée qui contient un nombre arbitraire de valeurs séparables. Cet extrait de la question ressemblerait à ceci:
def read_labeled_image_list(image_list_file):
"""Reads a .txt file containing pathes and labeles
Args:
image_list_file: a .txt file with one /path/to/image per line
label: optionally, if set label will be pasted after each line
Returns:
List with all filenames in file image_list_file
"""
f = open(image_list_file, 'r')
filenames = []
labels = []
for line in f:
filename, label = line[:-1].split(' ')
filenames.append(filename)
labels.append(int(label))
return filenames, labels
def read_images_from_disk(input_queue):
"""Consumes a single filename and label as a ' '-delimited string.
Args:
filename_and_label_tensor: A scalar string tensor.
Returns:
Two tensors: the decoded image, and the string label.
"""
label = input_queue[1]
file_contents = tf.read_file(input_queue[0])
example = tf.image.decode_png(file_contents, channels=3)
return example, label
# Reads pfathes of images together with their labels
image_list, label_list = read_labeled_image_list(filename)
images = ops.convert_to_tensor(image_list, dtype=dtypes.string)
labels = ops.convert_to_tensor(label_list, dtype=dtypes.int32)
# Makes an input queue
input_queue = tf.train.slice_input_producer([images, labels],
num_epochs=num_epochs,
shuffle=True)
image, label = read_images_from_disk(input_queue)
# Optional Preprocessing or Data Augmentation
# tf.image implements most of the standard image augmentation
image = preprocess_image(image)
label = preprocess_label(label)
# Optional Image and Label Batching
image_batch, label_batch = tf.train.batch([image, label],
batch_size=batch_size)
Voir aussi les exemples generic_input_producer à partir des exemples TensorVision pour le pipeline d'entrée complet.
Il existe trois étapes principales pour résoudre ce problème:
Remplissez tf.train.string_input_producer()
avec une liste de chaînes contenant la chaîne originale, délimitée par des espaces, contenant le nom de fichier et l'étiquette.
Utilisez tf.read_file(filename)
plutôt que tf.WholeFileReader()
pour lire vos fichiers image. tf.read_file()
est une opération sans état qui utilise un seul nom de fichier et génère une seule chaîne contenant le contenu du fichier. L'avantage est que c'est une fonction pure, il est donc facile d'associer des données à l'entrée et à la sortie. Par exemple, votre read_my_file_format
fonction deviendrait:
def read_my_file_format(filename_and_label_tensor):
"""Consumes a single filename and label as a ' '-delimited string.
Args:
filename_and_label_tensor: A scalar string tensor.
Returns:
Two tensors: the decoded image, and the string label.
"""
filename, label = tf.decode_csv(filename_and_label_tensor, [[""], [""]], " ")
file_contents = tf.read_file(filename)
example = tf.image.decode_png(file_contents)
return example, label
Invoquer la nouvelle version de read_my_file_format
en passant un seul élément retiré de la file d'attente de la input_queue
:
image, label = read_my_file_format(input_queue.dequeue())
Vous pouvez ensuite utiliser les tenseurs image
et label
dans le reste de votre modèle.
En plus des réponses fournies, il y a peu d'autres choses que vous puissiez faire:
Encodez votre étiquette dans le nom du fichier. Si vous avez N catégories différentes, vous pouvez renommer vos fichiers comme suit: 0_file001, 5_file002, N_file003
. Ensuite, lorsque vous lisez les données d’un lecteurkey, value = reader.read(filename_queue)
, votre clé/valeur est:
La sortie de Read sera un nom de fichier (clé) et le contenu de ce fichier (valeur)
Ensuite, analysez votre nom de fichier, extrayez l’étiquette et convertissez-la en int. Cela nécessitera un peu de prétraitement des données.
Utilisez TFRecords qui vous permettra de stocker les données et les étiquettes dans le même fichier.