利用TFRecords存儲與讀取帶標簽的圖片
覺得有用的話,歡迎一起討論相互學習~
TFRecords其實是一種二進制文件,雖然它不如其他格式好理解,但是它能更好的利用內存,更方便復制和移動,並且不需要單獨的標簽文件
TFRecords文件包含了tf.train.Example 協議內存塊(protocol buffer)(協議內存塊包含了字段 Features)。我們可以寫一段代碼獲取你的數據, 將數據填入到Example協議內存塊(protocol buffer),將協議內存塊序列化為一個字符串, 並且通過tf.python_io.TFRecordWriter 寫入到TFRecords文件。
從TFRecords文件中讀取數據, 可以使用tf.TFRecordReader的tf.parse_single_example解析器。這個操作可以將Example協議內存塊(protocol buffer)解析為張量。
我們使用tf.train.Example來定義我們要填入的數據格式,然后使用tf.python_io.TFRecordWriter來寫入。
基本的,一個Example中包含Features,Features里包含Feature(這里沒s)的字典。最后,Feature里包含有一個 FloatList, 或者ByteList,或者Int64List
示例代碼
# Reuse the image from earlier and give it a fake label
# 復用之前的圖像,並賦予一個假標簽
import tensorflow as tf
image_filename = "./images/chapter-05-object-recognition-and-classification/working-with-images/test-input-image.jpg"
# 獲得文件名列表
filename_queue = tf.train.string_input_producer(tf.train.match_filenames_once(image_filename))
# 生成文件名隊列
image_reader = tf.WholeFileReader()
_, image_file = image_reader.read(filename_queue)
# 通過閱讀器返回一個鍵值對,其中value表示圖像
image = tf.image.decode_jpeg(image_file)
# 通過tf.image.decode_jpeg解碼函數對圖片進行解碼,得到圖像.
sess = tf.Session()
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
sess.run(init_op)
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord, sess=sess)
print('the image is:', sess.run(image))
filename_queue.close(cancel_pending_enqueues=True)
coord.request_stop()
coord.join(threads)
image_label = b'\x01'
# Assume the label data is in a one-hot representation (00000001)
# 假設標簽數據位於一個獨熱的(one-hot)編碼表示中,(00000001) 二進制8位'x01'
# Convert the tensor into bytes, notice that this will load the entire image file
# 將張量轉換為字節型,注意這會加載整個圖像文件。
image_loaded = sess.run(image)
image_bytes = image_loaded.tobytes() # 將張量轉化為字節類型.
image_height, image_width, image_channels = image_loaded.shape
# Export TFRecord 導出TFRecord
writer = tf.python_io.TFRecordWriter("./output/training-image.tfrecord")
# Don't store the width, height or image channels in this Example file to save space but not required.
# 樣本文件中不保存圖像的寬度/高度和通道數,以便節省不要求分配的空間.
example = tf.train.Example(features=tf.train.Features(feature={
'label': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_label])),
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_bytes]))
}))
# This will save the example to a text file tfrecord
writer.write(example.SerializeToString()) # 序列化為字符串
writer.close()
# image = example.features.feature['image_bytes'].bytes_list.value
# label = example.features.feature['image_label'].int64_list.value
# 這樣的方式進行讀取.
"""標簽的格式被稱為獨熱編碼(one-hot encoding)這是一種用於多類分類的有標簽數據的常見的表示方法.
Stanford Dogs 數據集之所以被視為多類分類數據,是因為狗會被分類為單一品種,而非多個品種的混合,
在現實世界中,當預測狗的品種是,多標簽解決方案通常較為有效,因為他們能夠同時匹配屬於多個品種的狗"""
"""
這段代碼中,圖像被加載到內存中並被轉換為字節數組
image_bytes = image_loaded.tobytes()
然后通過tf.train.Example函數將values和labels以value的方式加載到example中,
example = tf.train.Example(features=tf.train.Features(feature={
'label': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_label])),
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_bytes]))
}))
example在寫入保存到磁盤之前需要先通過SerializeToString()方法將其序列化為二進制字符串.
序列化是一種將內存對象轉化為可安全傳輸到某種文件的格式.
上面序列化的樣本現在被保存為一種可被加載的格式,並可被反序列化為這里的樣本格式
由於圖像被保存為TFRecord文件,可以被再次從TFRecord文件加載.這樣比將圖像及其標簽分開加載會節省一些時間
"""
# Load TFRecord
# 加載TFRecord文件,獲取文件名隊列
tf_record_filename_queue = tf.train.string_input_producer(["./output/training-image.tfrecord"])
# Notice the different record reader, this one is designed to work with TFRecord files which may
# have more than one example in them.
# 注意這個不同的記錄讀取其,它的設計意圖是能夠使用可能會包含多個樣本的TFRecord文件
tf_record_reader = tf.TFRecordReader()
_, tf_record_serialized = tf_record_reader.read(tf_record_filename_queue)
# 通過閱讀器讀取value值,並保存為tf_record_serialized
# The label and image are stored as bytes but could be stored as int64 or float64 values in a
# serialized tf.Example protobuf.
# 標簽和圖像都按字節存儲,但也可按int64或float64類型存儲於序列化的tf.Example protobuf文件中
tf_record_features = tf.parse_single_example( # 這是一個模板化的東西,大部分都是這么寫的
tf_record_serialized,
features={
'label': tf.FixedLenFeature([], tf.string),
'image': tf.FixedLenFeature([], tf.string),
})
"""
class FixedLenFeature(collections.namedtuple(
"FixedLenFeature", ["shape", "dtype", "default_value"])):"""
"""Configuration for parsing a fixed-length input feature.
用於解析固定長度的輸入特性的配置。
To treat sparse input as dense, provide a `default_value`; otherwise,
the parse functions will fail on any examples missing this feature.
把稀疏的輸入看作是稠密的,提供一個默認值;否則,解析函數將缺少屬性值的情況下報錯。
Fields:
shape: Shape of input data.輸入數據的形狀
dtype: Data type of input.輸入數據類型
default_value: Value to be used if an example is missing this feature. It
must be compatible with `dtype` and of the specified `shape`.
如果一個示例缺少屬性值,那么將使用該默認值。它必須與dtype和指定的形狀兼容。
"""
# 但是在實際使用的過程中這里的features的是根據原先的保存時的名字對應的,而數據類型可以自行選取.
# Using tf.uint8 because all of the channel information is between 0-255
# 使用tf.uint8類型,因為所有的通道信息都處於0~255的范圍內
tf_record_image = tf.decode_raw(
tf_record_features['image'], tf.uint8)
# tf.decode_raw()函數將將字符串的字節重新解釋為一個數字的向量。
# Reshape the image to look like the image saved, not required
# 調整圖像的尺寸,使其與保存的圖像類似,但這並不是必需的
tf_record_image = tf.reshape(
tf_record_image,
[image_height, image_width, image_channels])
# Use real values for the height, width and channels of the image because it's required
# 用是指表示圖像的高度,寬度和通道,因為必須對輸入的形狀進行調整
# to reshape the input.
tf_record_label = tf.cast(tf_record_features['label'], tf.string)
sess.close()
sess = tf.InteractiveSession()
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
sess.run(init_op)
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord, sess=sess)
print("equal the image before and now", sess.run(tf.equal(image, tf_record_image))) # 檢查原始圖像和加載后的圖像是否一致
"""首先,按照與其他文件相同的方式加載該文件,主要區別在於該文件主要有TFRecordReaader對象讀取.
tf.parse_single_example對TFRecord進行解析,然后圖像按原始字節(tf.decode_raw)進行讀取"""
print("The lable of the image:", sess.run(tf_record_label)) # 輸出圖像的標簽
tf_record_filename_queue.close(cancel_pending_enqueues=True)
coord.request_stop()
coord.join(threads)
Notice
如果你想要復用這段代碼,請將 image_filename, tf.python_io.TFRecordWriter, tf.train.string_input_producer 等處的文件保存參數修改成你自己的圖片所在位置.
大圖是這樣的,運行請下載小圖.
參考資料
面向機器智能的Tensorflow實踐