简体   繁体   English

从字符串列表创建TfRecords并在解码后在tensorflow中提供图

[英]Creating TfRecords from a list of strings and feeding a Graph in tensorflow after decoding

The aim was to create a database of TfRecords. 目的是创建一个TfRecords数据库。 Given: I have 23 folders each contain 7500 image, and 23 text file, each with 7500 line describing features for the 7500 images in separate folders. 给出:我有23个文件夹,每个文件夹包含7500张图像,还有23个文本文件,每个文件都有7500行,分别描述了7500张图像在不同文件夹中的功能。

I created the database through this code: 我通过以下代码创建了数据库:

import tensorflow as tf
import numpy as np
from PIL import Image

def _Float_feature(value):
    return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))

def _bytes_feature(value):
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _int64_feature(value):
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

def create_image_annotation_data():
    # Code to read images and features.
    # images represent a list of numpy array of images, and features_labels represent a list of strings
    # where each string represent the whole set of features for each image. 
    return images, features_labels

# This is the starting point of the program.
# Now I have the images stored as list of numpy array, and the features as list of strings.
images, annotations = create_image_annotation_data()

tfrecords_filename = "database.tfrecords"
writer = tf.python_io.TFRecordWriter(tfrecords_filename)

for img, ann in zip(images, annotations):

    # Note that the height and width are needed to reconstruct the original image.
    height = img.shape[0]
    width = img.shape[1]

    # This is how data is converted into binary
    img_raw = img.tostring()
    example = tf.train.Example(features=tf.train.Features(feature={
        'height': _int64_feature(height),
        'width': _int64_feature(width),
        'image_raw': _bytes_feature(img_raw),
        'annotation_raw': _bytes_feature(tf.compat.as_bytes(ann))
    }))

    writer.write(example.SerializeToString())

writer.close()

reconstructed_images = []

record_iterator = tf.python_io.tf_record_iterator(path=tfrecords_filename)

for string_record in record_iterator:
    example = tf.train.Example()
    example.ParseFromString(string_record)

    height = int(example.features.feature['height']
                 .int64_list
                 .value[0])

    width = int(example.features.feature['width']
                .int64_list
                .value[0])

    img_string = (example.features.feature['image_raw']
                  .bytes_list
                  .value[0])

    annotation_string = (example.features.feature['annotation_raw']
                         .bytes_list
                         .value[0])

    img_1d = np.fromstring(img_string, dtype=np.uint8)
    reconstructed_img = img_1d.reshape((height, width, -1))
    annotation_reconstructed = annotation_string.decode('utf-8')

Therefore, after converting images and text into tfRecords and after being able to read them and convert images into numpy and the (binary text) into string in python, I tried to go the extra mile by using a filename_queue with a reader (The purpose was to provide the graph with batch of data rather one peace of data at a time. Additionally, the aim was to enqueue and dequeue the queue of examples through different threads, therefore, making training the network faster) 因此,在将图像和文本转换为tfRecords并能够读取它们并将图像转换为numpy并将(二进制文本)转换为python中的字符串之后,我尝试通过使用带有读取器的filename_queue来加倍努力(目的是为图表提供一批数据,而不是一次提供和平数据。此外,其目的是通过不同的线程使示例队列入队和出队,因此,可以更快地训练网络)

Therefore, I used the following code: 因此,我使用以下代码:

import tensorflow as tf
import numpy as np
import time

image_file_list = ["database.tfrecords"]
batch_size = 16

# Make a queue of file names including all the JPEG images files in the relative
# image directory.
filename_queue = tf.train.string_input_producer(image_file_list, num_epochs=1, shuffle=False)

reader = tf.TFRecordReader()

# Read a whole file from the queue, the first returned value in the tuple is the
# filename which we are ignoring.
_, serialized_example = reader.read(filename_queue)

features = tf.parse_single_example(
      serialized_example,
      # Defaults are not specified since both keys are required.
      features={
          'height': tf.FixedLenFeature([], tf.int64),
          'width': tf.FixedLenFeature([], tf.int64),
          'image_raw': tf.FixedLenFeature([], tf.string),
          'annotation_raw': tf.FixedLenFeature([], tf.string)
      })

image = tf.decode_raw(features['image_raw'], tf.uint8)
annotation = tf.decode_raw(features['annotation_raw'], tf.float32)

height = tf.cast(features['height'], tf.int32)
width = tf.cast(features['width'], tf.int32)

image = tf.reshape(image, [height, width, 3])

# Note that the minimum after dequeue is needed to make sure that the queue is not empty after dequeuing so that
# we don't run into errors
'''
min_after_dequeue = 100
capacity = min_after_dequeue + 3 * batch_size
ann, images_batch = tf.train.batch([annotation, image],
                                   shapes=[[1], [112, 112, 3]],
                                   batch_size=batch_size,
                                   capacity=capacity,
                                   num_threads=1)
'''

# Start a new session to show example output.
with tf.Session() as sess:
    merged = tf.summary.merge_all()
    train_writer = tf.summary.FileWriter('C:/Users/user/Documents/tensorboard_logs/New_Runs', sess.graph)

    # Required to get the filename matching to run.
    tf.global_variables_initializer().run()

    # Coordinate the loading of image files.
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

    for steps in range(16):
        t1 = time.time()
        annotation_string, batch, summary = sess.run([annotation, image, merged])
        t2 = time.time()
        print('time to fetch 16 faces:', (t2 - t1))
        print(annotation_string)
        tf.summary.image("image_batch", image)
        train_writer.add_summary(summary, steps)

    # Finish off the filename queue coordinator.
    coord.request_stop()
    coord.join(threads)

Finally, after running the above code, I got the following error: OutOfRangeError (see above for traceback): FIFOQueue '_0_input_producer' is closed and has insufficient elements (requested 1, current size 0) [[Node: ReaderReadV2 = ReaderReadV2[_device="/job:localhost/replica:0/task:0/cpu:0"](TFRecordReaderV2, input_producer)]] 最后,在运行上述代码之后,我得到以下错误: OutOfRangeError(请参见上面的回溯):FIFOQueue'_0_input_producer'已关闭并且元素不足(要求1,当前大小为0)[[节点:ReaderReadV2 = ReaderReadV2 [_device = “ / job:localhost /副本:0 / task:0 / cpu:0”] [(TFRecordReaderV2,input_producer)]]

Another Question: 另一个问题:

  1. How to decode binary database (tfrecords) to retrieve back the features stored "as python string data structure". 如何解码二进制数据库(tfrecords)以检索“作为python字符串数据结构”存储的功能。
  2. How to use the tf.train.batch to create a batch of examples to feed the network. 如何使用tf.train.batch创建一批示例来馈送网络。

Thank you!! 谢谢!! Any help is much appreciated. 任何帮助深表感谢。

In order to solve this problem, the coordinator along with the queue runner both had to be initialized within a Session . 为了解决这个问题, coordinatorqueue runner都必须在Session初始化。 Additionally, since the number of epoch is controlled internally, it is not a global variable , instead, consider a local variable . 此外,由于纪元数是内部控制的,因此它不是global variable ,而是考虑local variable Therefore, we need to initialize that local variable before telling the queue_runner to start the enqueuing the file_names into the Queue . 因此,我们需要在告诉queue_runner开始将file_names排队入Queue之前初始化该局部变量。 Therefore, here is the following code: 因此,下面是以下代码:

filename_queue = tf.train.string_input_producer(tfrecords_filename, num_epochs=num_epoch, shuffle=False, name='queue')
reader = tf.TFRecordReader()

key, serialized_example = reader.read(filename_queue)
features = tf.parse_single_example(
    serialized_example,
    # Defaults are not specified since both keys are required.
    features={
        'height': tf.FixedLenFeature([], tf.int64),
        'width': tf.FixedLenFeature([], tf.int64),
        'image_raw': tf.FixedLenFeature([], tf.string),
        'annotation_raw': tf.FixedLenFeature([], tf.string)
    })
...
init_op = tf.group(tf.local_variables_initializer(),
               tf.global_variables_initializer())
with tf.Session() as sess:
    sess.run(init_op)

    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

And now should work. 现在应该可以了。

Now to gather a batch of images before feeding them into the network, we can use tf.train.shuffle_batch or tf.train.batch . 现在要收集一批图像,然后再将它们输入网络,我们可以使用tf.train.shuffle_batchtf.train.batch Both works. 两者都可以。 And the difference is simple. 区别很简单。 One shuffles the images and the other not. 一个混洗图像,另一个不混洗。 But note that, defining a number a threads and using tf.train.batch might shuffle the data samples because of the race that takes part between the threads that are enqueuing file_names . 但是请注意,由于线程在将file_names排队的线程之间参与竞争,因此为线程定义一个数字并使用tf.train.batch可能会使数据样本混洗。 Anyways, the following code should be inserted directly after initializing the Queue as follows: 无论如何,在初始化Queue之后应立即插入以下代码:

min_after_dequeue = 100
num_threads = 1
capacity = min_after_dequeue + num_threads * batch_size
label_batch, images_batch = tf.train.batch([annotation, image],
                                       shapes=[[], [112, 112, 3]],
                                       batch_size=batch_size,
                                       capacity=capacity,
                                       num_threads=num_threads)

Note that here the shape of the tensors could be different. 请注意,这里的tensors形状可能不同。 It happened that the reader was decoding a colored image of size [112, 112, 3] . 碰巧阅读器正在解码大小为[112, 112, 3]的彩色图像。 And the annotation has a [] (there is no reason, that was a particular case). 并且注释具有[] (没有理由,这是一种特殊情况)。

Finally, we can treat the tf.string datatype as a string. 最后,我们可以将tf.string数据类型视为字符串。 In reality, after evaluating the annotation tensor, we can realize that the tensor is treated as a binary string (This is how it is really treated in tensorflow). 实际上,在评估注释张量后,我们可以意识到张量被视为binary string (这是在张量流中真正对待它的方式)。 Therefore, in my case that string was just a set of features related to that particular image. 因此,在我的情况下,字符串只是与该特定图像相关的一组功能。 Therefore, in order to extract specific features, here is an example: 因此,为了提取特定功能,下面是一个示例:

# The output of string_split is not a tensor, instead, it is a SparseTensorValue. Therefore, it has a property value that stores the actual values. as a tensor. 
label_batch_splitted = tf.string_split(label_batch, delimiter=', ')
label_batch_values = tf.reshape(label_batch_splitted.values, [batch_size, -1])
# string_to_number will convert the feature's numbers into float32 as I need them. 
label_batch_numbers = tf.string_to_number(label_batch_values, out_type=tf.float32)
# the tf.slice would extract the necessary feature which I am looking.
confidences = tf.slice(label_batch_numbers, begin=[0, 3], size=[-1, 1])

Hope this answer helps. 希望这个答案有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM