基于Tensorflow高阶读写教程
前言
tensorflow提供了多种读写方式,我们最常见的就是使用tf.placeholder()这种方法,使用这个方法需要我们提前处理好数据格式,不过这种处理方法也有缺陷:不便于存储和不利于分布式处理,因此,TensorFlow提供了一个标准的读写格式和存储协议,不仅如此,TensorFlow也提供了基于多线程队列的读取方式,高效而简洁,读取速度也更快,据一个博主说速度能提高10倍,相当的诱人.【下面的实验均是在tensorflow1.0的环境下进行】
tensorflow的example解析
example协议
在TensorFlow官方github文档里面,有个example.proto的文件,这个文件详细说明了TensorFlow里面的example协议,下面我将简要叙述一下。
tensorflow的example包含的是基于key-value对的存储方法,其中key是一个字符串,其映射到的是feature信息,feature包含三种类型:
BytesList:字符串列表
FloatList:浮点数列表
Int64List:64位整数列表
以上三种类型都是列表类型,意味着都能够进行拓展,但是也是因为这种弹性格式,所以在解析的时候,需要制定解析参数,这个稍后会讲。
在TensorFlow中,example是按照行读的,这个需要时刻记住,比如存储
tf.tain.example
官方给了一个example的例子:
AnExampleforamovierecommendationapplication:
features{
feature{
key:"age"
value{float_list{
value:29.0
}}
}
feature{
key:"movie"
value{bytes_list{
value:"TheShawshankRedemption"
value:"FightClub"
}}
}
feature{
key:"movie_ratings"
value{float_list{
value:9.0
value:9.7
}}
}
feature{
key:"suggestion"
value{bytes_list{
value:"Inception"
}}
}
上面的例子中包含一个features,features里面包含一些feature,和之前说的一样,每个feature都是由键值对组成的,其key是一个字符串,其value是上面提到的三种类型之一。
Example中有几个一致性规则需要注意:
如果一个example的featureK的数据类型是TT,那么所有其他的所有featureK都应该是这个数据类型
featureK的valuelist的item个数可能在不同的example中是不一样多的,这个取决于你的需求
如果在一个example中没有featurek,那么如果在解析的时候指定一个默认值的话,那么将会返回一个默认值
如果一个featurek不包含任何的value值,那么将会返回一个空的tensor而不是默认值
tf.train.SequenceExample
sequence_example表示的是一个或者多个sequences,同时还包括上下文context,其中,context表示的是feature_lists的总体特征,如数据集的长度等,feature_list包含一个key,一个value,value表示的是features集合(feature_lists),同样,官方源码也给出了sequence_example的例子:
//ontext:{
feature:{
key:"locale"
value:{
bytes_list:{
value:["pt_BR"]
}
}
}
feature:{
key:"age"
value:{
float_list:{
value:[19.0]
}
}
}
feature:{
key:"favorites"
value:{
bytes_list:{
value:["MajestyRose","SavannahOuten","OneDirection"]
}
}
}
}
feature_lists:{
feature_list:{
key:"movie_ratings"
value:{
feature:{
float_list:{
value:[4.5]
}
}
feature:{
float_list:{
value:[5.0]
}
}
}
}
feature_list:{
key:"movie_names"
value:{
feature:{
bytes_list:{
value:["TheShawshankRedemption"]
}
}
feature:{
bytes_list:{
value:["FightClub"]
}
}
}
}
feature_list:{
key:"actors"
value:{
feature:{
bytes_list:{
value:["TimRobbins","MorganFreeman"]
}
}
feature:{
bytes_list:{
value:["BradPitt","EdwardNorton","HelenaBonhamCarter"]
}
}
}
}
}
一致性的sequence_example遵循以下规则:
1、context中,所有featurek要保持数据类型一致性
2、一些example中的某些feature_listsL可能会丢失,如果在解析的时候允许为空的话,那么在解析的时候回返回一个空的list
3、feature_lists可能是空的
4、如果一个feature_list是非空的,那么其里面的所有feature都必须是一个数据类型
5、如果一个feature_list是非空的,那么对于里面的feature的长度是不是需要一样的,这个取决于解析时候的参数
tensorflow的parseexample解析
在官方代码*[parsing_ops.py]*中有关于parseexample的详细介绍,我在这里再叙述一下。
tf.parse_example
来看tf.parse_example的方法定义:
defparse_example(serialized,features,name=None,example_names=None)
parse_example是把example解析为词典型的tensor
参数含义:
serialized:一个batch的序列化的example
features:解析example的规则
name:当前操作的名字
example_name:当前解析example的proto名称
这里重点要说的是第二个参数,也就是features,features是把serialized的example中按照键值映射到三种tensor:1,VarlenFeature2,SparseFeature3,FixedLenFeature
下面对这三种映射方式做一个简要的叙述:
VarlenFeature
是按照键值把example的value映射到SpareTensor对象,假设我们有如下的serialized数据:
serialized=[
features
{feature{key:"ft"value{float_list{value:[1.0,2.0]}}}},
features
{feature[]},
features
{feature{key:"ft"value{float_list{value:[3.0]}}}
]
使用VarLenFeatures方法:
features={
"ft":tf.VarLenFeature(tf.float32)
}
那么我们将得到的是:
{"ft":SparseTensor(indices=[[0,0],[0,1],[2,0]],
values=[1.0,2.0,3.0],
dense_shape=(3,2))}
可见,显示的indices是ft值的索引,values是值,dense_shape是indices的shape
FixedLenFeature
而FixedLenFeature是按照键值对将features映射到大小为[serilized.size(),df.shape]的矩阵,这里的FixLenFeature指的是每个键值对应的feature的size是一样的。对于上面的例子,如果使用:
features:{
"ft":FixedLenFeature([2],dtype=tf.float32,default_value=-1),
}
那么我们将得到:
{"ft":[[1.0,2.0],[3.0,-1.0]]}
可见返回的值是一个[2,2]的矩阵,如果返回的长度不足给定的长度,那么将会使用默认值去填充。
【注意:】
事实上,在TensorFlow1.0环境下,根据官方文档上的内容,我们是能够得到VarLenFeature的值,但是得不到FixLenFeature的值,因此建议如果使用定长的FixedLenFeature,一定要保证对应的数据是等长的。
做个试验来说明:
#coding=utf-8
importtensorflowastf
importos
keys=[[1.0],[],[2.0,3.0]]
sess=tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
defmake_example(key):
example=tf.train.Example(features=tf.train.Features(
feature={
'ft':tf.train.Feature(float_list=tf.train.FloatList(value=key))
}
))
returnexample
filename="tmp.tfrecords"
ifos.path.exists(filename):
os.remove(filename)
writer=tf.python_io.TFRecordWriter(filename)
forkeyinkeys:
ex=make_example(key)
writer.write(ex.SerializeToString())
writer.close()
reader=tf.TFRecordReader()
filename_queue=tf.train.string_input_producer(["tmp.tfrecords"],num_epochs=1)
_,serialized_example=reader.read(filename_queue)
#coord=tf.train.Coordinator()
#threads=tf.train.start_queue_runners(sess=sess,coord=coord)
batch=tf.train.batch(tensors=[serialized_example],batch_size=3)
features={
"ft":tf.VarLenFeature(tf.float32)
}
#key_parsed=tf.parse_single_example(make_example([1,2,3]).SerializeToString(),features)
key_parsed=tf.parse_example(batch,features)
#startthequeue
printtf.contrib.learn.run_n(key_parsed)
#[]meansscalar
features={
"ft":tf.FixedLenFeature(shape=[2],dtype=tf.float32)
}
key_parsed=tf.parse_example(batch,features)
printtf.contrib.learn.run_n(key_parsed)
结果返回如下:
[{'ft':SparseTensorValue(indices=array([[0,0],
[2,0],
[2,1]]),values=array([1.,2.,3.],dtype=float32),dense_shape=array([3,2]))}]
InvalidArgumentError(seeabovefortraceback):Name:,Key:ft,Index:0.Numberoffloatvalues!=expected.Valuessize:1butoutputshape:[2]
可见,对于VarLenFeature,是能返回正常结果的,但是对于FixedLenFeature则返回size不对,可见如果对于边长的数据还是不要使用FixedLenFeature为好。
如果把数据设置为[[1.0,2.0],[2.0,3.0]],那么FixedLenFeature返回的是:
[{'ft':array([[1.,2.],
[2.,3.]],dtype=float32)}]
这是正确的结果。
SparseFeature可以从下面的例子来说明:
`serialized`:
```
[
features{
feature{key:"val"value{float_list{value:[0.5,-1.0]}}}
feature{key:"ix"value{int64_list{value:[3,20]}}}
},
features{
feature{key:"val"value{float_list{value:[0.0]}}}
feature{key:"ix"value{int64_list{value:[42]}}}
}
]
```
Andarguments
```
example_names:["input0","input1"],
features:{
"sparse":SparseFeature(
index_key="ix",value_key="val",dtype=tf.float32,size=100),
}
```
Thentheoutputisadictionary:
```python
{
"sparse":SparseTensor(
indices=[[0,3],[0,20],[1,42]],
values=[0.5,-1.0,0.0]
dense_shape=[2,100]),
}
```
现在明白了Example的协议和tf.parse_example的方法之后,我们再看看看几个简单的parse_example
tf.parse_single_example
区别于tf.parse_example,tf.parse_single_example只是少了一个batch而已,其余的都是一样的,我们看代码:
#coding=utf-8
importtensorflowastf
importos
sess=tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
defmake_example(key):
example=tf.train.Example(features=tf.train.Features(
feature={
'ft':tf.train.Feature(float_list=tf.train.FloatList(value=key))
}
))
returnexample
features={
"ft":tf.FixedLenFeature(shape=[3],dtype=tf.float32)
}
key_parsed=tf.parse_single_example(make_example([1.0,2.0,3.0]).SerializeToString(),features)
printtf.contrib.learn.run_n(key_parsed)
结果返回为:
[{'ft':array([1.,2.,3.],dtype=float32)}]
tf.parse_single_sequence_example
tf.parse_single_sequence_example对应的是tf.train,SequenceExample,我们以下面代码说明,single_sequence_example的用法:
#coding=utf-8
importtensorflowastf
importos
keys=[[1.0,2.0],[2.0,3.0]]
sess=tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
defmake_example(locale,age,score,times):
example=tf.train.SequenceExample(
context=tf.train.Features(
feature={
"locale":tf.train.Feature(bytes_list=tf.train.BytesList(value=[locale])),
"age":tf.train.Feature(int64_list=tf.train.Int64List(value=[age]))
}),
feature_lists=tf.train.FeatureLists(
feature_list={
"movie_rating":tf.train.FeatureList(feature=[tf.train.Feature(float_list=tf.train.FloatList(value=score))foriinrange(times)])
}
)
)
returnexample.SerializeToString()
context_features={
"locale":tf.FixedLenFeature([],dtype=tf.string),
"age":tf.FixedLenFeature([],dtype=tf.int64)
}
sequence_features={
"movie_rating":tf.FixedLenSequenceFeature([3],dtype=tf.float32,allow_missing=True)
}
context_parsed,sequence_parsed=tf.parse_single_sequence_example(make_example("china",24,[1.0,3.5,4.0],2),context_features=context_features,sequence_features=sequence_features)
printtf.contrib.learn.run_n(context_parsed)
printtf.contrib.learn.run_n(sequence_parsed)
结果打印为:
[{'locale':'china','age':24}]
[{'movie_rating':array([[1.,3.5,4.],
[1.,3.5,4.]],dtype=float32)}]
tf.parse_single_sequence_example的自动补齐
在常用的文本处理方面,由于文本经常是非定长的,因此需要经常补齐操作,例如使用CNN进行文本分类的时候就需要进行padding操作,通常我们把padding的索引设置为0,而且在文本预处理的时候也需要额外的代码进行处理,而TensorFlow提供了一个比较好的自动补齐工具,就是在tf.train.batch里面把参数dynamic_pad设置成True,样例如下:
#coding=utf-8
importtensorflowastf
importos
keys=[[1,2],[2]]
sess=tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
defmake_example(key):
example=tf.train.SequenceExample(
context=tf.train.Features(
feature={
"length":tf.train.Feature(int64_list=tf.train.Int64List(value=[len(key)]))
}),
feature_lists=tf.train.FeatureLists(
feature_list={
"index":tf.train.FeatureList(feature=[tf.train.Feature(int64_list=tf.train.Int64List(value=[key[i]]))foriinrange(len(key))])
}
)
)
returnexample.SerializeToString()
filename="tmp.tfrecords"
ifos.path.exists(filename):
os.remove(filename)
writer=tf.python_io.TFRecordWriter(filename)
forkeyinkeys:
ex=make_example(key)
writer.write(ex)
writer.close()
reader=tf.TFRecordReader()
filename_queue=tf.train.string_input_producer(["tmp.tfrecords"],num_epochs=1)
_,serialized_example=reader.read(filename_queue)
#coord=tf.train.Coordinator()
#threads=tf.train.start_queue_runners(sess=sess,coord=coord)
context_features={
"length":tf.FixedLenFeature([],dtype=tf.int64)
}
sequence_features={
"index":tf.FixedLenSequenceFeature([],dtype=tf.int64)
}
context_parsed,sequence_parsed=tf.parse_single_sequence_example(
serialized=serialized_example,
context_features=context_features,
sequence_features=sequence_features
)
batch_data=tf.train.batch(tensors=[sequence_parsed['index']],batch_size=2,dynamic_pad=True)
result=tf.contrib.learn.run_n({"index":batch_data})
printresult
打印结果如下:
[{'index':array([[1,2],
[2,0]])}]
可见还是比较好用的功能
tensorflow的TFRecords读取
在上面的部分,我们展示了关于tensorflow的example的用法和解析过程,那么我们该如何使用它们呢?其实在上面的几段代码里面也有体现,就是TFRecords进行读写,TFRecords读写其实很简单,tensorflow提供了两个方法:
tf.TFRecordReader
tf.TFRecordWriter
首先我们看下第二个,也就是tf.TFRecordWritre,之所以先看第二个的原因是第一个Reader将和batch一起在下一节讲述。
关于TFRecordWriter,可以用下面代码说明,假设serilized_object是一个已经序列化好的example,那么其写的过程如下:
writer=tf.python_io.TFRecordWriter(filename) writer.write(serilized_object) writer.close()
tensorflow的多线程batch读取
这一节主要关注的是基于TFRecords的读取的方法和batch操作,我们可以回看一下之前的文章的batch操作:
Batching defread_my_file_format(filename_queue): reader=tf.SomeReader() key,record_string=reader.read(filename_queue) example,label=tf.some_decoder(record_string) processed_example=some_processing(example) returnprocessed_example,label definput_pipeline(filenames,batch_size,num_epochs=None): filename_queue=tf.train.string_input_producer( filenames,num_epochs=num_epochs,shuffle=True) example,label=read_my_file_format(filename_queue) #min_after_dequeuedefineshowbigabufferwewillrandomlysample #from--biggermeansbettershufflingbutslowerstartupandmore #memoryused. #capacitymustbelargerthanmin_after_dequeueandtheamountlarger #determinesthemaximumwewillprefetch.Recommendation: #min_after_dequeue+(num_threads+asmallsafetymargin)*batch_size min_after_dequeue=10000 capacity=min_after_dequeue+3*batch_size example_batch,label_batch=tf.train.shuffle_batch( [example,label],batch_size=batch_size,capacity=capacity, min_after_dequeue=min_after_dequeue) returnexample_batch,label_batch
这里我们把tf.SomeReader()换成tf.TFRecordReader()即可,然后再把tf.some_decoder换成我们自定义的decoder,当然在decoder里面我们可以自己指定parser(也就是上文提到的内容),然后我们使用tf.train.batch或者tf.train.shuffle_batch等操作获取到我们需要送入网络训练的batch参数即可。
多线程读取batch实例
我使用了softmax回归做一个简单的示例,下面是一个多线程读取batch的实例主要代码:
#coding=utf-8
"""
author:luchi
date:24/4/2017
desc:traininglogisticregression
"""
importtensorflowastf
frommodelimportLogistic
defread_my_file_format(filename_queue):
reader=tf.TFRecordReader()
_,serilized_example=reader.read(filename_queue)
#parsingexample
features=tf.parse_single_example(serilized_example,
features={
"data":tf.FixedLenFeature([2],tf.float32),
"label":tf.FixedLenFeature([],tf.int64)
}
)
#decodefromrawdata,thereindeeddonottochange,buttoshowcommonstep,iwriteacasehere
#data=tf.cast(features['data'],tf.float32)
#label=tf.cast(features['label'],tf.int64)
returnfeatures['data'],features['label']
definput_pipeline(filenames,batch_size,num_epochs=100):
filename_queue=tf.train.string_input_producer([filenames],num_epochs=num_epochs)
data,label=read_my_file_format(filename_queue)
datas,labels=tf.train.shuffle_batch([data,label],batch_size=batch_size,num_threads=5,
capacity=1000+3*batch_size,min_after_dequeue=1000)
returndatas,labels
classconfig():
data_dim=2
label_num=2
learining_rate=0.1
init_scale=0.01
defrun_training():
withtf.Graph().as_default(),tf.Session()assess:
datas,labels=input_pipeline("reg.tfrecords",32)
c=config()
initializer=tf.random_uniform_initializer(-1*c.init_scale,1*c.init_scale)
withtf.variable_scope("model",initializer=initializer):
model=Logistic(config=c,data=datas,label=labels)
fetches=[model.train_op,model.accuracy,model.loss]
feed_dict={}
#init
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(sess=sess,coord=coord)
try:
whilenotcoord.should_stop():
#fetches=[model.train_op,model.accuracy,model.loss]
#feed_dict={}
#feed_dict[model.data]=sess.run(datas)
#feed_dict[model.label]=sess.run(labels)
#_,accuracy,loss=sess.run(fetches,feed_dict)
_,accuracy,loss=sess.run(fetches,feed_dict)
print("thelossis%fandtheaccuracyis%f"%(loss,accuracy))
excepttf.errors.OutOfRangeError:
print("donetraining")
finally:
coord.request_stop()
coord.join(threads)
sess.close()
defmain():
run_training()
if__name__=='__main__':
main()
这里有几个坑需要说明一下:
使用了string_input_producer指定num_epochs之后,在初始化的时候需要使用:
init_op=tf.group(tf.global_variables_initializer(), tf.local_variables_initializer()) sess.run(init_op)
要不然会报错
2.使用了从文件读取batch之后,就不需要设置tf.placeholder了【非常重要】,我在这个坑里呆了好久,如果使用了tf.placeholder一是会报错为tensor对象能送入到tf.placeholder中,另外一个是就算使用sess.run(batch_data),也会存在模型不能收敛的问题,所以切记切记
结果显示如下:
thelossis0.156685andtheaccuracyis0.937500 thelossis0.185438andtheaccuracyis0.968750 thelossis0.092628andtheaccuracyis0.968750 thelossis0.059271andtheaccuracyis1.000000 thelossis0.088685andtheaccuracyis0.968750 thelossis0.271341andtheaccuracyis0.968750 thelossis0.244190andtheaccuracyis0.968750 thelossis0.136841andtheaccuracyis0.968750 thelossis0.115607andtheaccuracyis0.937500 thelossis0.080254andtheaccuracyis1.000000
完整的代码见我的GitHub
以上这篇基于Tensorflow高阶读写教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。