tensorflow-TFRecord 檔案詳解
TFRecord 是 tensorflow 內建的檔案格式,它是一種二進位制檔案,具有以下優點:
1. 統一各種輸入檔案的操作
2. 更好的利用記憶體,方便複製和移動
3. 將二進位制資料和標籤(label)儲存在同一個檔案中
引言
在瞭解如下操作後進一步詳細講解TFRecord
tf.train.Int64List(value=list_data)
它的作用是 把 list 中每個元素轉換成 key-value 形式,
注意,輸入必須是 list,且 list 中元素型別要相同,且與 Int 保持一致;
# value = tf.constant([1, 2]) ### 這會報錯的 ss = 1 ### Int64List 對應的元素只能是 int long,其他同理 tt = 2 out1 = tf.train.Int64List(value = [ss, tt]) print(out1) # value: 1 # value: 2 ss = [1 ,2] out2 = tf.train.Int64List(value = ss) print(out2) # value: 1 # value: 2
同類型的 方法還有 2 個
tf.train.FloatList tf.train.BytesList
tf.train.Feature(int64_list=)
它的作用是 構建 一種型別的特徵集,比如 整型
out = tf.train.Feature(int64_list=tf.train.Int64List(value=[33, 22])) print(out) # int64_list { # value: 33 # value: 22 # }
也可以是其他型別
tf.train.Feature(float_list=tf.train.FloatList()) tf.train.Feature(bytes_list=tf.train.BytesList())
tf.train.Features(feature=dict_data)
它的作用是 構建 多種型別 的特徵集,可以 dict 格式表達 多種型別
ut = tf.train.Features(feature={ "suibian": tf.train.Feature(int64_list=tf.train.Int64List(value=[1, 2, 4])), "a": tf.train.Feature(float_list=tf.train.FloatList(value=[5., 7.])) }) print(out) # feature { # key: "a" # value { # float_list { # value: 5.0 # value: 7.0 # } # } # } # feature { # key: "suibian" # value { # int64_list { # value: 1 # value: 2 # value: 4 # } # } # }
tf.train.Example(features=tf.train.Features())
它的作用是建立一個 樣本,Example 對應一個樣本
example = tf.train.Example(features= tf.train.Features(feature={ 'a': tf.train.Feature(int64_list=tf.train.Int64List(value=range(2))), 'b': tf.train.Feature(bytes_list=tf.train.BytesList(value=[b'm',b'n'])) })) print(example) # features { # feature { # key: "a" # value { # int64_list { # value: 0 # value: 1 # } # } # } # feature { # key: "b" # value { # bytes_list { # value: "m" # value: "n" # } # } # } # }
一幅圖總結一下上面的程式碼
Example 協議塊
它其實是一種 資料儲存的 格式,類似於 xml、json 等;
用上述方法實現該格式;
一個 Example 協議塊對應一個樣本,一個樣本有多種特徵,每種特徵下有多個元素,可參看上圖;
message Example{ Features features = 1; } message Features{ map<string,Features> feature = 1; } message Feature { oneof kind { BytesList bytes_list = 1; FloateList float_list = 2; Int64List int64_list = 3; } }
TFRecord 檔案就是以 Example協議塊 格式 儲存的;
TFRecord 檔案
該類檔案具有寫功能,且可以把其他型別的檔案轉換成該型別檔案,其實相當於先讀取其他檔案,再寫入 TFRecord 檔案;
該類檔案也具有讀功能;
TFRecord 儲存
儲存分兩步:
1.建立儲存器
2. 構造每個樣本的 Example 協議塊
tf.python_io.TFRecordWriter(file_name)
構造儲存器,儲存器有兩個常用方法
- write(record):向檔案中寫入一個樣本
- close():關閉儲存器
注意:此處的 record 為一個序列化的 Example,通過 Example.SerializeToString()
來實現,它的作用是將 Example 中的 map 壓縮為二進位制,節約大量空間
示例程式碼1:將 MNIST 資料集儲存成 TFRecord 檔案
import tensorflow as tf import numpy as np import input_data # 生成整數型的屬性 def _int64_feature(value): return tf.train.Feature(int64_list = tf.train.Int64List(value = [value])) # 生成字串型別的屬性,也就是影象的內容 def _string_feature(value): return tf.train.Feature(bytes_list = tf.train.BytesList(value = [value])) # 讀取影象資料 和一些屬性 mniset = input_data.read_data_sets('../../../data/MNIST_data',dtype=tf.uint8, one_hot=True) images = mniset.train.images labels = mniset.train.labels pixels = images.shape[1] # (55000, 784) num_examples = mniset.train.num_examples # 55000 file_name = 'output.tfrecords' ### 檔名 writer = tf.python_io.TFRecordWriter(file_name) ### 寫入器 for index in range(num_examples): ### 遍歷樣本 image_raw = images[index].tostring() ### 圖片轉成 字元型 example = tf.train.Example(features = tf.train.Features(feature = { 'pixel': _int64_feature(pixels), 'label': _int64_feature(np.argmax(labels[index])), 'image_raw': _string_feature(image_raw) })) writer.write(example.SerializeToString()) ### 寫入 TFRecord writer.close()
示例程式碼2:將 csv 儲存成 TFRecord 檔案
train_frame = pd.read_csv("../myfiles/xx3.csv") train_labels_frame = train_frame.pop(item="label") train_values = train_frame.values train_labels = train_labels_frame.values print("values shape: ", train_values.shape) # values shape: (2, 3) print("labels shape:", train_labels.shape) # labels shape: (2,) writer = tf.python_io.TFRecordWriter("xx3.tfrecords") for i in range(train_values.shape[0]): image_raw = train_values[i].tostring() example = tf.train.Example( features=tf.train.Features( feature={ "image_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_raw])), "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[train_labels[i]])) } ) ) writer.write(record=example.SerializeToString()) writer.close()
示例3:將 png 檔案儲存成 TFRecord 檔案
# filenames = tf.train.match_filenames_once('../myfiles/*.png') filenames = glob.iglob('..\myfiles\*.png') writer = tf.python_io.TFRecordWriter('png.tfrecords') for filename in filenames: img = Image.open(filename) img_raw = img.tobytes() label = 1 example = tf.train.Example( features=tf.train.Features( feature={ "image_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])), "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])) } ) ) writer.write(record=example.SerializeToString()) writer.close()
TFRecord 讀取
讀取檔案 和 tensorflow 讀取資料方法類似,參考我的部落格 讀取資料
tf.TFRecordReader()
建立讀取器,有 read 和 close 方法
tf.parse_single_example(serialized,features=None,name= None)
解析單個 Example 協議塊
- serialized : 標量字串的Tensor,一個序列化的Example,檔案經過檔案閱讀器之後的value
- features :字典資料,key為讀取的名字,value為FixedLenFeature
- return : 一個鍵值對組成的字典,鍵為讀取的名字
features中的value還可以為tf.VarLenFeature(),但是這種方式用的比較少,它返回的是SparseTensor資料,這是一種只儲存非零部分的資料格式,瞭解即可。
tf.FixedLenFeature(shape,dtype)
- shape : 輸入資料的形狀,一般不指定,為空列表
- dtype : 輸入資料型別,與儲存進檔案的型別要一致,型別只能是float32,int 64, string
- return : 返回一個定長的 Tensor (即使有零的部分也儲存)
示例程式碼
filename = 'png.tfrecords' file_queue = tf.train.string_input_producer([filename], shuffle=True) reader = tf.TFRecordReader() key, value = reader.read(file_queue) ### features 的 key 必須和 寫入時 一致,資料型別也必須一致,shape 可為 空 dict_data= tf.parse_single_example(value, features={'label': tf.FixedLenFeature(shape=(1,1), dtype=tf.int64), 'image_raw': tf.FixedLenFeature(shape=(), dtype=tf.string)}) label = tf.cast(dict_data['label'], tf.int32) img = tf.decode_raw(dict_data['image_raw'], tf.uint8) ### 將 string、bytes 轉換成 int、float image_tensor = tf.reshape(img, [500, 500, -1]) sess = tf.Session() sess.run(tf.local_variables_initializer()) tf.train.start_queue_runners(sess=sess) while 1: # print(sess.run(key)) # b'png.tfrecords:0' image = sess.run(image_tensor) img_PIL = Image.fromarray(image) img_PIL.show()
參考資料:
https://blog.csdn.net/chengshuhao1991/article/details/78656724
https://www.cnblogs.com/yanshw/articles/12419616.html