為什么要用tfrecords文件格式
背景問題是深度學(xué)習(xí)的訓(xùn)練數(shù)據(jù)很大懦砂,這些數(shù)據(jù)要一次性加載到內(nèi)存中初厚,對硬件的要求太高。TensorFlow推薦使用tfrcords文件格式來保存數(shù)據(jù)虱颗。這種格式適合以串行方式讀取大批量的數(shù)據(jù)椎眯。如果不使用tfrecords處理,那么訓(xùn)練集上成千上萬的圖片就是分散的一個個文件存放的再姑,訓(xùn)練過程中要讀取的時候一個個讀取會非常慢萌抵。但是如果整合成若干個tfrecord文件,那么讀取會變得很快元镀。
生成绍填、寫tfrecords的具體過程
數(shù)據(jù)準備
把一個很大的訓(xùn)練集,比如210000張24x24的小圖片栖疑,全部放大一個list中讨永,然后轉(zhuǎn)換成np.array類型的train_data中。train_data的shape是[210000蔽挠,24住闯,24,1]澳淑。把這210000張的目標(biāo)結(jié)果先用list保存,如果是二分類插佛,此時list保存的是0杠巡,1兩種取值。先通過np.array 轉(zhuǎn)換成[210000,1]的形狀雇寇,然后通過keras.utils.to_categorical轉(zhuǎn)換成onehot編碼氢拥,并reshape最后得到train_labels的形狀是[210000,2]
數(shù)據(jù)拆分
210000個數(shù)據(jù)原來是210000張圖片,訓(xùn)練時一張一張讀取很消耗時間锨侯。我們的目標(biāo)是把210000張的數(shù)據(jù)轉(zhuǎn)存到100份tfrecord文件中嫩海。這樣子要讀取數(shù)據(jù)的時候,就可以通過大文件的tfrecord批量讀取囚痴。生成沒份tfrecord的時候叁怪,這里需要用2100張數(shù)據(jù)。每張數(shù)據(jù)是24*24個浮點數(shù)據(jù)深滚。
對于一組2100張生成一個tfrecord文件的過程
生成數(shù)據(jù)的byte表示
取出第j張24*24的浮點數(shù)據(jù)數(shù)據(jù) data[j] 和2D向量label[j]奕谭,把這兩個列表轉(zhuǎn)成bytes數(shù)據(jù)img_str = np.array(data[j]).tobytes()
label_str = np.array(label[j]).tobytes()
。 np.array(data[j]).tobytes()
相當(dāng)于把data[j]列表中的24x24個浮點數(shù)據(jù)痴荐,轉(zhuǎn)換成了連續(xù)的byte表示血柳。轉(zhuǎn)換后的數(shù)據(jù)格式形式如下b"\xee\xedm?\xc0\xbf??\xd5......
相當(dāng)于把內(nèi)存中的二進制表現(xiàn)用文本體現(xiàn)出來了。
組裝tf.train.Example
把一張圖片組裝成一個example
image_example(img_str, label_str)
image_example的實現(xiàn)參考tensoeflow的官網(wǎng)
def image_example(img_str, label_str)
feature = {
'label': _bytes_feature(label),
'image_raw':_bytes_feature(img_str),
}
example = tf.train.Example(features =
tf.train.Features(feature = feature))
return example
其中_bytes_feature是把數(shù)據(jù)組裝成feature的官網(wǎng)推薦實現(xiàn)
def _bytes_feature(value):
if isinstance(value, type(tf.constant(0))):
value = value.numpy()
return tf.train.Feature(bytes_list = tf.train.BytesList(value = [value]))
把組裝好的example依次寫入tfrecord文件
示意代碼如下:
with tf.io.TFRecordWriter(filePath) as tfWriter:
for i in X_elements:
data_str = data_I.tobytes
label_str = label_I.tobytes
tfExample = image_example(data_str, label_str)
tfWriter.write(tfExample.SerializeToString())
讀取tfrecord的具體過程
把所有的.tfrecords
文件放到一個列表中tfrecordsFileList
生兆,通過train_data_set = tf.data.TFRecordDataset(tfrecordsFileList)
來一個一個讀取tfrecord文件难捌。
tf.train.Example的用法
tf.train.Feature
tf.train.Feature的本質(zhì)是一個lis, 其中l(wèi)ist只存放三種類型數(shù)據(jù),bytes, int64 或者 float
int_feature = tf.train.Feature(int64_list=tf.train.Int64List(value=[1, 2, 3, 4]))
表示創(chuàng)建一個tf.train.Feature對象,對象中的list類型是int64_list類型. 數(shù)據(jù)是把value的一個普通list轉(zhuǎn)換成的tf.train.Int64List類型.
bytes_feature = tf.train.Feature(bytes_list=tf.train.BytesList(value=[b"abc", b"1234"]))
表示創(chuàng)建一個tf.train.Feature對象,對象中的list類型是byte類型. 數(shù)據(jù)是把value的一個普通list轉(zhuǎn)換成的tf.train.BytesList類型.
tf.train.Features 和 tf.train.Example
通過下面的層級方式構(gòu)建出的example對象, 表示這個example對象實際有3個主體列表數(shù)據(jù).分別是一個名為my_ints的整數(shù)列表, 一個名為my_floats的浮點數(shù)列表,一個名為mybytes的bytes型列表.
example = tf.train.Example(features=tf.train.Features(feature={
'my_ints': int_feature,
'my_floats': float_feature,
'my_bytes': bytes_feature,
}))
example對象的好處就是可以調(diào)用SerializeToString()函數(shù)把example的數(shù)據(jù)進行字節(jié)序列化. 下面的例子可以說明這個特點
def serialize_example(feature0, feature1, feature2, feature3):
feature = {
'feature0': _int64_feature(feature0),
'feature1': _int64_feature(feature1),
'feature2': _bytes_feature(feature2),
'feature3': _float_feature(feature3),
}
example_proto = tf.train.Example(features=tf.train.Features(feature=feature))
return example_proto.SerializeToString()
serialized_example = serialize_example(False, 4, b'goat', 0.9876)
print(serialized_example)
在上面的代碼中,serialized_example = serialize_example(False, 4, b'goat', 0.9876)
把4個關(guān)聯(lián)一個元素的feature (False, 4, b'goat', 0.9876)
組合成了features并放入了一個example中,通過example的SerializeToString 輸出了一個連續(xù)的byte類型數(shù)據(jù)如下
b'\nR\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04[\xd3|?\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04'
轉(zhuǎn)換成上述的byte類型數(shù)據(jù)就方便把很多的元素數(shù)據(jù)寫成文件.方便后期的讀取了.這個就是tfrecord的主要思路.