日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tensorflow2.0 环境下的tfrecord读写及tf.io.parse_example和tf.io.parse_single_example的区别

發布時間:2023/12/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tensorflow2.0 环境下的tfrecord读写及tf.io.parse_example和tf.io.parse_single_example的区别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在文章tfrecord格式的內容解析及樣例?中我們已經分析了tfrecord 的內容是什么格式,接下來就要學習tfrecord怎么使用,及tfrecord的讀寫。

生成tfrecord

tfrecord文件的寫入非常簡單,仍然用tfrecord格式的內容解析及樣例?中的例子,我們首先生成一個example

value_city = u"北京".encode('utf-8') # 城市 value_use_day = 7 #最近7天打開淘寶次數 value_pay = 289.4 # 最近7 天消費金額 value_poi = [b"123", b"456", b"789"] #最近7天瀏覽電鋪''' 下面生成ByteList,Int64List和FloatList ''' bl_city = tf.train.BytesList(value = [value_city]) ## tf.train.ByteList入參是list,所以要轉為list il_use_day = tf.train.Int64List(value = [value_use_day]) fl_pay = tf.train.FloatList(value = [value_pay]) bl_poi = tf.train.BytesList(value = value_poi)''' 下面生成tf.train.Feature ''' feature_city = tf.train.Feature(bytes_list = bl_city) feature_use_day = tf.train.Feature(int64_list = il_use_day) feature_pay = tf.train.Feature(float_list = fl_pay) feature_poi = tf.train.Feature(bytes_list = bl_poi) ''' 下面定義tf.train.Features ''' feature_dict = {"city":feature_city,"use_day":feature_use_day,"pay":feature_pay,"poi":feature_poi} features = tf.train.Features(feature = feature_dict) ''' 下面定義tf.train.example ''' example = tf.train.Example(features = features)

然后就是把這個example寫入文件中

path = "./tfrecord" with tf.io.TFRecordWriter(path) as file_writer:file_writer.write(example.SerializeToString())

至此,就完成了tfrecord文件的寫入。

當然,到這里還沒完,用tf.io寫入example的字節和直接用Python的寫入example的字節 是一樣的嗎? 為此我們做一個實驗

path = "./tfrecord" path2 = "./tfrecord2" with tf.io.TFRecordWriter(path) as file_writer:file_writer.write(example.SerializeToString()) with open(path2,"wb") as f:f.write(example.SerializeToString())

通過上面的代碼,我們分別通過tf.io和Python的open方法把example的字節寫入2個文件。比較大小后發現一個是86字節,一個是99字節。看來內容還是不一樣的,所以不能用Python自帶的open方法代替tf.io

tfrecord讀取

tfrecord的讀取也很簡單,但是tensorflow的官方document寫的真的非常糟糕,以下全部是我個人摸索出來的結果。接上代碼

path = "./tfrecord" data = tf.data.TFRecordDataset(pathtensor)

以上實際上就已經完成了tfrecord的讀取過程。很多人會說,可是無論平時使用還是工程中,都會用一個map方法對data進行變換呀。沒錯,如果使用需要進行變換,這是因為我們在保存tfrecord的時候,先把一個example序列化成二進制,然后再把二進制字節變成一個string,這樣每個example就是一個string保存在了tfrecord 中。而讀取過程同樣,通過tf.data.TFRecordDataset,我們已經把每個example變成的string以? tf.tensor(dtype=string) ?的方式讀取進來了。所以我們完全可以用下面代碼看讀取結果

for batch in data:print(batch)result: tf.Tensor(b'\nQ\n\x18\n\x03poi\x12\x11\n\x0f\n\x03123\n\x03456\n\x03789\n\x12\n\x04city\x12\n\n\x08\n\x06\xe5\x8c\x97\xe4\xba\xac\n\x10\n\x07use_day\x12\x05\x1a\x03\n\x01\x07\n\x0f\n\x03pay\x12\x08\x12\x06\n\x043\xb3\x90C', shape=(), dtype=string)

這里還有另外一個大坑,data是一個TFRecordDatasetV2類,但同時,它也是個可迭代對象,所以就算找遍它的所有屬性和方法,都找不到它保存數據的tensor,但是可以通過迭代看到。

在Python中,可迭代對象是指有__iter__屬性的對象,這類對象可以用循環取迭代,所以可以放在for中迭代,其他對象例如整型,float等不是可迭代對象,放在循環中會報錯 “object is not iterable”。

當然只是把example序列化的字節,讀取出來是不能用的,我們還是要把其中數據解析出來,這時候就要用到熟悉的map 方法了

def decode_fn(record_bytes):return tf.io.parse_single_example(record_bytes,{"city":tf.io.FixedLenFeature([],dtype = tf.string),"use_day":tf.io.FixedLenFeature([],dtype = tf.int64),"pay":tf.io.FixedLenFeature([],dtype = tf.float32),"poi":tf.io.VarLenFeature(dtype=tf.string)}) data2 = data.map(decode_fn)

tf.io.parse_single_example? 輸入是一個string的tensor 輸出是一個 dict ,格式就是如入參中的格式,應該注意的是,入參中的key應該去全部在example中出現過,否則會報錯。

在弄懂了data的內容之后,我們就可以通過下面的方法調用decode_fn:

for batch in data:print(decode_fn(batch))result: {'poi': <tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x000002532FEF7860>, 'city': <tf.Tensor: id=55, shape=(), dtype=string, numpy=b'\xe5\x8c\x97\xe4\xba\xac'>, 'pay': <tf.Tensor: id=56, shape=(), dtype=float32, numpy=289.4>, 'use_day': <tf.Tensor: id=58, shape=(), dtype=int64, numpy=7>}

可以看到2種讀取方法內容是一樣的。

在這里還有一個問題,在tf的官方教程中,io接口下有2個很類似的函數:tf.io.parse_single_example和tf.io.parse_example。這兩個有什么區別呢?

1. 解析的example規模不同。

我們先來看官方的文檔

tf.io.parse_example的官方文檔如下

Args

serializedA vector (1-D Tensor) of strings, a batch of binary serialized?Example?protos.
featuresA?dict?mapping feature keys to?FixedLenFeature,?VarLenFeature,?SparseFeature, and?RaggedFeature?values.
example_namesA vector (1-D Tensor) of strings (optional), the names of the serialized protos in the batch.
nameA name for this operation (optional).

Returns

A?dict?mapping feature keys to?Tensor,?SparseTensor, and?RaggedTensor?values.

tf.io.parse_single_example官方文檔如下

Args

serializedA scalar string Tensor, a single serialized Example.
featuresA?dict?mapping feature keys to?FixedLenFeature?or?VarLenFeature?values.
example_names(Optional) A scalar string Tensor, the associated name.
nameA name for this operation (optional).

Returns

A?dict?mapping feature keys to?Tensor?and?SparseTensor?values.

通過官方給的定義和函數的名字就可以看出來,tf.io.parse_single_example只對單條example的二進制序列進行解析,得到的也就是一個example,所以他的第一個入參要求是scalar string Tensor,即標量tensor,其實就是一個字符串。所以在上面的例子中

for batch in data:print(batch)result: tf.Tensor(b'\nQ\n\x18\n\x03poi\x12\x11\n\x0f\n\x03123\n\x03456\n\x03789\n\x12\n\x04city\x12\n\n\x08\n\x06\xe5\x8c\x97\xe4\xba\xac\n\x10\n\x07use_day\x12\x05\x1a\x03\n\x01\x07\n\x0f\n\x03pay\x12\x08\x12\x06\n\x043\xb3\x90C', shape=(), dtype=string)

result看似是一個tensor,但它沒有形狀,所以說本質上還是一個標量(字符串),并非張量

tensorflow中有三個概念

標量(scalar tensor),也可以認為就是普通的變量,是0階張量,shape一般是空

向量(vector),就是一階張量

張量,不用解釋,用的最多

那如果把標量變形成一個向量或者張量,這樣的入參不符合parse_single_example的入參定義,就會報錯

而tf.io.parse_example正好相反,tf.io.parse_example可以解析一批example,所以他的入參是一個向量,就算是只對一個example進行解析,也必須把標量變形成向量,也就是說應該寫成

def decode_fn(record_bytes):return tf.io.parse_example(tf.reshape(record_bytes,[1]), #注意這一行發生了變化{"city":tf.io.FixedLenFeature([],dtype = tf.string),"use_day":tf.io.FixedLenFeature([],dtype = tf.int64),"pay":tf.io.FixedLenFeature([],dtype = tf.float32),"poi":tf.io.VarLenFeature(dtype=tf.string)}) data2 = data.map(decode_fn)

這里應該注意,tf.io.parse_example的第一個入參只能是向量,絕對不能是二維以上的張量,否則同樣報錯。

2.對可變長sparse特征的解析結果不同

這個區別是非常有趣的,我們來看上面的poi這個特征,他是一個sparse特征,無論是通過tf.io.parse_example 還是tf.io.parse_single_example,我們都是把字符串解析了出來,得到了?["123", "456", "789"]三個店鋪id,但實際上一般都要對這類特征進行onehot,變成數值類型的輸入。

用tf.io.parse_example得到的onrhot編碼是一個向量例如,假設一共有5家店鋪[a,"123", b, "456", "789"]。那么用tf.io.parse_example,在經過onehot會得到[0,1,0,1,1],而parse_single_example會得到

[[0,1,0,0,0]

[0,0,0,1,0]

0,0,0,0,1]]

這個會在https://blog.csdn.net/kangshuangzhu/article/details/106851826中詳細介紹

?

結語

這里還有一個問題,在定義tf.io.parse_single_example的時候,我們需要給出返回的dict的形式。當特征數量較少的時候這當然沒問題,但是工程中一般特征非常多,動輒上千維,用這種方法定義很明顯是非常低效的。這時候tf.feature_column就是一個非常有用的工具了。tf.feature_column的內容下一篇文章再進行講解

?

?

總結

以上是生活随笔為你收集整理的tensorflow2.0 环境下的tfrecord读写及tf.io.parse_example和tf.io.parse_single_example的区别的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。