tf api
TensorFlow学习笔记1:graph、session和op
Session与变量的关系:变量的具体值是依存于session的,下面第二个sess会报未初始化的错,即使第一个sess里已经初始化了变量,但随着第一个sess的关闭,变量的值会随着sess的关闭而消失,但图上的节点只要定义了就一直存在,这是因为Tensor是只是数据的一个引用,sess关闭,引用虽然存在,但是数据已经不存在了,新开一个sess,是取不到前一个sess里的变量的值
import tensorflow as tf
v1=tf.Variable([[1,2],[3,4]])
v2=tf.Variable([[1,2],[5,6]])
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(tf.global_variables())
sess.run(tf.assign(v1,[[10,20],[5,6]]))
print(sess.run(tf.global_variables()))
with tf.Session() as sess:
# 报错,因为没有初始化
print(sess.run(tf.global_variables()))
TensorFlow基础知识:计算图中的Op,边,和张量
之前搞不清楚op和tensor的关系,op是操作(比如加减乘除),有输入有输出,tensor是对数据(比如输入和计算结果)的引用。下面这句话对理解tf的工作模式非常有帮助
计算图的定义和图的运算是分开的.tensorflow是一个’符号主义的库’.编程模式分为两类,命令式(imperative style)和符号式(symbolic style).命令式的程序很容易理解和调试,它按照原有的逻辑运行.符号式则相反,在现有的深度学习框架中,torch是命令式的,Caffe,Mxnet是两种模式的混合,tensorflow完全采用符号式.符号式编程,一般先定义各种变量,然后建立一个计算图(数据流图),计算图指定了各个变量之间的计算关系,此时对计算图进行编译,没有任何输出,计算图还是一个空壳,只有把需要运算的输入放入后,才会在模型中形成数据流.形成输出.
看下面简单的一段代码,之前我一直会怀疑,run了两次,那是不是就inference这个函数在图上就执行了两次啊?不是的,执行的不是inference函数,而是数据向前流动,inference函数是仅仅在定义图上的计算节点,虽然说最后train_op会被run两次,run是在graph上,数据有两次流入。而inference这个函数也只是在图上定义op而已,其他的活并不是在inference函数里完成的,而是在graph上完成的
import tensorflow as tf
def inference(x):
net = tf.layers.dense(x, 1)
return net
x = tf.placeholder(tf.float32, shape=[None, 4])
y = tf.placeholder(tf.float32, shape=[None, 1])
y_ = inference(x)
loss = tf.reduce_mean(y - y_)
train_op = tf.train.AdamOptimizer().minimize(loss)
with tf.Session() as sess:
sess.run(train_op,feed_dict={x:[[1,2,3,4]],y:[[1]]})
sess.run(train_op,feed_dict={x:[[1,2,3,4]],y:[[1]]})
Tensorflow一些常用基本概念与函数(2)
tensorflow编程: Inputs and Readers,有place_holder相关和FIFOQueue相关
Inside TF-Slim(13) preprocessing(图像增强相关)
在tensorflow里,类型很重要,很多操作里,只接受float或者int,而且很多时候要求两个tensor的类型一致
Variable和get_variable的用法以及区别
tf.reset_default_graph()
a=tf.get_variable('13',shape=[],initializer=tf.constant_initializer(12))
# 下一个语句报错
# a=tf.get_variable('13',shape=[],initializer=tf.constant_initializer(12))
b=tf.Variable(12,name='13')
print(b)
b=tf.Variable(12,name='13')
print(b)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(a))
print(sess.run(b))
Why do we use tf.name_scope()
tf.variable_scope和tf.name_scope的用法
下面的代码可以看出,name_scope只对op和Variable有效,即对其名称可以添加scope头,get_variable是先尝试获取,如果已经存在并且此时不是复用(没有指定reuse)那就报错,如果没有就创建。
with tf.name_scope('V1'):
a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))
a2 = tf.Variable(tf.random_normal(shape=[2, 3], mean=0, stddev=1), name='a2')
add = tf.add(a1, a2)
a3 = tf.Variable(tf.random_normal(shape=[2, 3], mean=0, stddev=1), name='a2')
with tf.name_scope('V2'):
a4 = tf.Variable(tf.random_normal(shape=[2, 3], mean=0, stddev=1), name='a2')
# a5 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))报错,因为a1已经存在了
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(a1.name) # a1:0
print(a2.name) # V1/a2:0
print(add) # Tensor("V1/Add:0", shape=(2, 3), dtype=float32)
print(a3.name) # V1/a2_1:0
print(a4.name) # V2/a2:0
下面的代码可以看出,只要外层variable_scope是reuse,内层无论reuse是什么,都是reuse
with tf.variable_scope('name') as scope:
net = tf.get_variable('net',shape=[],initializer=tf.ones_initializer)
with tf.variable_scope('in'):
net1 = tf.get_variable('net1',shape=[],initializer=tf.ones_initializer)
print(net)
print(net1)
with tf.variable_scope('name',reuse=True) as scope:
net = tf.get_variable('net',shape=[],initializer=tf.ones_initializer)
with tf.variable_scope('in',reuse=False):
net1 = tf.get_variable('net1',shape=[],initializer=tf.ones_initializer)
print(net)
print(net1)
tensorflow更改变量的值
tf之中对于数据的处理一定要用tf的操作,比如判断某个tensor的值是否与某个值相等,一定要用tf.equal(tensor,1)这样来比较,不能直接==
Tensorflow变量与张量
Tensor不存数据,只是存储数据的来源,因此一切取出tensor的值的操作都要在sess里进行
Spatial Dropout
import numpy as np
import tensorflow as tf
ary = np.arange(70).reshape((2, 7, 5))
inputs = tf.Variable(ary,dtype=tf.float32)
output = tf.nn.dropout(inputs,keep_prob=0.5,noise_shape=[2,1,5])
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(output))
noise_shape:不指定的话,就是随机drop值,如果指定了,比如第二位为1,代表着第二维度的每一列要drop整个第二维全drop,要是不drop那就全留着
tf.gradients()中grad_ys的作用
可以把文中例子改了,改成grad_ys=None看输出有什么变化
grad_ys is a list of tensors of the same length as ys that holds the initial gradients for each y in ys
这个参数的意义在于对xs中的每个元素的求导加权种
关于word2vec的skip-gram模型使用负例采样nce_loss损失函数的源码剖析
- weights: A Tensor of shape [num_classes, dim], or a list of Tensor objects whose concatenation along dimension 0 has shape [num_classes, dim]. The (possibly-partitioned) class embeddings.
dim就是embedding_size,嵌入的维度- biases: A Tensor of shape [num_classes]. The class biases.
- labels: A Tensor of type int64 and shape [batch_size, num_true]. The target classes.
训练数据样本对应的类别矩阵,比如skip-gram里,每个中心词的上下文都是这个中心词的label,以- inputs: A Tensor of shape [batch_size, dim]. The forward activations of the input network.
就是在基于输入的嵌入后的向量,每个样本都是中心词经过嵌入后的向量
inputs和labels是两两配对的一个格式,比如一个中心词,上下文为1,文本为‘ABC’,那么就可以生成两个样本B->A,B->C;在输入的时候,要将B转化成嵌入向量,而A,C不用,直接是字典中的单次编号就可以,也就是0~num_classes中的一个值- num_sampled: An int. The number of classes to randomly sample per batch.
- num_classes: An int. The number of possible classes.
num_class是单词表的大小- num_true: An int. The number of target classes per training example…
每个训练数据对应的类别数目,这个我不太理解,难道一个样本里,一个中心词可以对应多个上下文?比如。。B->(A,C)???
tf.reset_default_graph()
g=tf.Graph()
with g.as_default():
tf.reset_default_graph()
上述代码报错,但如果我要清空当前nest graph怎么办,Do not use tf.reset_default_graph() to clear nested graphs. If you need a cleared graph, exit the nesting and create a new graph.
tf.reset_default_graph()
g=tf.Graph()
with g.as_default():
pass
g=tf.Graph()
# g里面的东西就清空了
tf.newaxis的用法
#[:, tf.newaxis]操作相当于把这个一维向量变成了一个很高的二维矩阵
arr=tf.constant([1,2])
tf.Session() as sess:
print(sess.run(arr))
print(sess.run(arr[:,tf.newaxis]))
TensorFlow queue多线程读取数据
tf.control_dependencies()
TensorFlow笔记——(2) tf.group(), tf.tuple 和 tf.identity()
tf.identity的意义以及用例
tensorflow中batch normalization的用法
博主有提到说,“一般来讲,这些参数都是基于channel来做的”,那么也就是说,在CV领域做BN的时候,求平均值是对于通道来求的,因为假设“输入x是一个16*32*32*128(NWHC格式)的feature map”,那么当前层就可以看做一个输入为32*32*128的神经层,每个神经元可以relu或者其他,当对这玩意做bn的时候,是对每个通道求均值和方差,比如第一个通道是一个16*32*32的feature map,对这16*32*32个数求均值和方差,用这个均值和方差处理当前通道的feature map,以上都是个人理解,但我觉得是对的,因为
其中axis的用法,推荐去看tf.layers.BatchNormalization中API的描述,比如输入的是一个batch,这个batch是100*15,也就是100个样本,每个样本15维度,当axis=1的时候,就是说,认为第一个轴是特征轴,对这个轴进行bn,那么算得的均值也是15维度的,就是说有15个均值,这也正是batch_normalization所做的。
至于为什么刚才图片里的是128个均值和方差,我猜是进行了广播吧
6.20得到验证,bn.weights是个列表,有四个Tensor,分别是均值方差以及对应的滑动量,他们的形状都是一维度的长度和channal一样,都是3
import tensorflow as tf
tf.reset_default_graph()
input_x = tf.Variable([[[[1.,2.,3.]],[[4.,5.,6.]]]])
bn = tf.layers.BatchNormalization()
output=bn(input_x)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(output)
print(bn.weights)
print(sess.run(output))
tensorflow中的batch_norm以及tf.control_dependencies和tf.GraphKeys.UPDATE_OPS的探究
为什么要updata_op,简单说,就是训练的时候,每次用的是本次batch里的数据计算mean和variance,但是预测的时候,用的是好多个mean和variance的滑动平均值来作为mean和variance的,而根据《google实战》那本书里讲,滑动平均实际上是维护的新的影子变量,因此需要手动更新这些影子变量
TENSORFLOW GUIDE: BATCH NORMALIZATION
tensorflow在函数中用tf.Print输出中间值的方法
WARNING:tensorflow:From E:/txtingwang/python/feature_extraction/zxy_test.py:5: Print (from tensorflow.python.ops.logging_ops) is deprecated and will be removed after 2018-08-20.
Instructions for updating:
Use tf.print instead of tf.Print. Note that tf.print returns a no-output operator that directly prints the output. Outside of defuns or eager mode, this operator will not be executed unless it is directly specified in session.run or used as a control dependency for other operators. This is only a concern in graph mode. Below is an example of how to ensure tf.print executes in graph mode:
就是说,tf.Print已经被删除了,换成tf.print了。tf.print就方便多了,就只是一个打印操作,不像tf.Print那么麻烦了,不过上面博客里讲的道理还是适用的
import tensorflow as tf
def test():
a = tf.constant(0)
# 如果把下一行放在了for里面,那么a_print就会打印10次了
# 想象运算是一个流,在run的时候,a_print只被定义了一次,只流了一次
a_print = tf.print(['a_value: ', a])
for i in range(10):
with tf.control_dependencies([a_print]):
a = tf.add(a, 1)
return a
if __name__ == '__main__':
sess = tf.Session()
with sess.as_default():
tensor = tf.range(10)
print_op = tf.print(tensor)
with tf.control_dependencies([print_op]):
out = tf.add(tensor, tensor)
sess.run(out)
with tf.Session() as sess:
print(sess.run(test()))
tile函数的用法,其实就是堆叠,下面的例子就是第一维度扩充重复两次,第二维度重复3次
import tensorflow as tf
a = tf.constant([[1, 2], [3, 4], [5, 6]], dtype=tf.float32)
a1 = tf.tile(a, [2, 3])
with tf.Session() as sess:
print(sess.run(a))
print(sess.run(a1))
经验干货:使用tf.py_func函数增加Tensorflow程序的灵活性
py_func在v2将会被废弃,更新方法推荐使用py_function,官方给的说明是tf.py_function, which takes a python function which manipulates tf eager tensors instead of numpy arrays. It’s easy to convert a tf eager tensor to a ndarray (just call tensor.numpy()) but having access to eager tensors means
tf.py_function
s can use accelerators such as GPUs as well as being differentiable using a gradient tape.也就是说,原来py_func处理的是ndarray,而新的py_function处理的是eager tensor,并且也告诉你怎么使用了,就是调用tensor.numpy()就行.其中有个参数叫Tout,如果说你的方法返回了两个list,比如说是[1,2,3],[4,5,6],那么Tout就应该是(tf.int32,tf.int32),代表返回了两个值,第一个值内的数字是tf.int32类型的,因为这两个list最终都会被包裹成tensor,而tensor的dtype就是这块Tout所需要指明的
import tensorflow as tf
import numpy as np
def tile_tensor(tensor_a, tensor_b):
tile_tensor_a = tf.py_function(_tile_tensor, [tensor_a, tensor_b], tf.float32)
return tile_tensor_a
def _tile_tensor(a, b):
#这里a和b不再是ndarray了,因为用了py_function
tile_a = np.tile(a.numpy(), (b.numpy().shape[0], 1))
return tile_a
TensorFlow里的losses包下求loss只能求一个样本的pre和true之间的loss,以hinge loss为例
SVM(支持向量机)之Hinge Loss解释
tf.reset_default_graph()
#下面是个multilabel问题,但仍然是一个样本计算loss
loss = tf.losses.hinge_loss([1,1],[1,1])
loss = tf.losses.hinge_loss([0,1],[1,1])
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(loss))
【TensorFlow】sparse_softmax_cross_entropy_with_logits 和softmax_cross_entropy_with_logits选用技巧
tf.losses.get_loss和tf.losses.get_losses,regularization,从下面可以看出,get_xxx_loss是获取某种损失的列表,get_xxx_losses是获取某种损失的和。然后,正则化损失并不会被添加到loss_collection里,从下面可以看到,但是get_total_losses可以获得全部的损失,包括正则化损失和损失集合里的损失。API里描述get_total_losses有如下一句话
In particular, this adds any losses you have added with tf.add_loss() to any regularization losses that have been added by regularization parameters on layers constructors e.g. tf.layers.
特别强调,这个方法会将任何以tf.add_loss()方式添加的损失,和,所有的在定义神经层里时候定义的正则化损失加起来。
net = tf.Variable([[2.,3.],[1.,2.]])
dense = tf.layers.Dense(1, kernel_regularizer=tf.keras.regularizers.l2(l=0.0005 / 2))
net = dense(net)
print(tf.losses.get_regularization_loss())
# []
print(tf.losses.get_regularization_losses())
# Tensor("total_regularization_loss:0", shape=(), dtype=float32)
print(tf.losses.get_losses())
# []
print(tf.losses.get_total_loss())
# Tensor("total_loss:0", shape=(), dtype=float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(tf.losses.get_regularization_loss().eval())
# 0.000184326 有可能不同
print(sess.run(tf.losses.get_total_loss()))
# 0.000184326
下面的代码展示了sparse_softmax_cross_entropy
和sparse_softmax_cross_entropy_with_logits
的区别,前者是后者的一个高层封装,默认求和求平均,不加其他参数的话,前者返回一个数,后者返回一个列表分别代表每个样本的损失;前者默认将这个损失加入到tf.GraphKeys.LOSSES这个集合里,后者没这功能。
cross_entropy1 = tf.losses.sparse_softmax_cross_entropy(labels = [1,0,1],logits=[[1/2,1/2],[1/2,1/2],[0.9,1/3]])
cross_entropy2 = tf.nn.sparse_softmax_cross_entropy_with_logits(labels = [1,0,1],logits=[[1/2,1/2],[1/2,1/2],[0.9,1/3]])
total_loss=tf.losses.get_total_loss()
with tf.Session() as sess:
print(sess.run(cross_entropy1))
print(sess.run(cross_entropy2))
print(sess.run(total_loss))
feature column这个东西真的很好用,把feature columns送入estimator里,然后,我们不用再去关注如何对输入数据进行处理了,这些feature column会自动帮我们进行feature transformation
比如说现在有一个feature column是一个分桶形的feature column
读入dataset的时候,直接读取数字就行,不需要人工对dataset里的数字进行处理手动分桶
同样用iris_data为例,定义Estimator需要一个model_fn,model_fn里以前向传播为主要部分
在调用estimator的训练步骤中,即estimator.train,需要一个input_fn,根据官方doc这个input_fn的返回需要是一个dataset,其中每个元素都是(features,labels),这个两个东西直接作为model_fn的features和labels输入
dataset经过batch后,features就是一个(?,feature_shape)的张量元素,如果每个样本是一个28*28的图片,那么feature就是(?,28,28),而label也一样,如果仅仅是一个标记,那label就是(?,)的一个一维向量元素
inference的时候,你直接就可以吧feature想象成placeholder这个东西
def input_fn_closure2(file_path, epoch, batch_size):
FIELD_DEFAULTS = [[0.0], [0.0], [0.0], [0.0], [0]]
def input_fn():
def _parse_line(line):
# 解析每个元素
fields = tf.decode_csv(line, FIELD_DEFAULTS)
# fields的类型是list,与设想的不同,这个函数只会被执行一次
# 你可以在这个地方打印一个东西,你会发现这个打印操作只进行了1次
return fields[:-1], fields[-1]
# 跳过一个元素
dataset = tf.data.TextLineDataset(file_path).skip(1)
dataset = dataset.map(_parse_line)
print(dataset)
# 下面一行的作用是取类别为1的所有样本
# dataset = dataset.filter(lambda a, b: tf.equal(b, 1))
# 注意batch之后,dataset中存储的单位就变了
dataset = dataset.shuffle(1000).repeat(epoch).batch(batch_size)
print(dataset)
return dataset
return input_fn
def inference2(features, params):
print(features)
net = features
for num_units in params['hidden_units']:
net = tf.layers.dense(net, num_units, activation=tf.nn.relu)
logits = tf.layers.dense(net, params['n_classes'], activation=None)
return logits
def model_fn2(features, labels, mode, params):
logits = inference2(features, params)
predicted_class = tf.argmax(logits, axis=1)
if mode == tf.estimator.ModeKeys.PREDICT:
predictions = {
# 请比较带[:, tf.newaxis]和不带[:, tf.newaxis]的区别
'class_ids': predicted_class[:, tf.newaxis],
'probabilities': tf.nn.softmax(logits),
'logits': logits
}
return tf.estimator.EstimatorSpec(mode, predictions=predictions)
loss = tf.losses.sparse_softmax_cross_entropy(labels, logits)
accuracy = tf.metrics.accuracy(labels, predicted_class, name='acc_op')
metrics = {
'accuracy': accuracy
}
if mode == tf.estimator.ModeKeys.EVAL:
return tf.estimator.EstimatorSpec(mode, loss=loss, eval_metric_ops=metrics)
assert mode == tf.estimator.ModeKeys.TRAIN
optimizer = tf.train.AdamOptimizer(learning_rate=0.1)
train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)
def build_estimator2():
feature_columns = iris.get_feature_columns()
# 当然由于这个模型训练的太快= =2秒一存也存不够10个
my_checkpointing_config = tf.estimator.RunConfig(
save_checkpoints_secs=2, # Save checkpoints every 2 seconds.
keep_checkpoint_max=10, # Retain the 10 most recent checkpoints.
)
# 如果model_dir存在模型,那么就会直接读取文件夹下面最新的模型,并且检查文件模型和代码中模型是否兼容
classifier = tf.estimator.Estimator(model_fn=model_fn2, model_dir='guide/estimator_test/model/iris',
config=my_checkpointing_config,
params={'feature_columns': feature_columns,
# Two hidden layers of 10 nodes each.
'hidden_units': [10, 10],
# The model must choose between 3 classes.
'n_classes': 3,
})
return classifier
def train_eval_test2(train_file_path, epoch, batch_size, test_file_path):
model = build_estimator2()
model.train(input_fn=input_fn_closure2(train_file_path, epoch, batch_size), steps=1000)
print(model.evaluate(input_fn=iris.input_fn_closure2(test_file_path, 1, batch_size)))
expected = ['Setosa', 'Versicolor', 'Virginica']
predict_x = {
'SepalLength': [5.1, 5.9, 6.9],
'SepalWidth': [3.3, 3.0, 3.1],
'PetalLength': [1.7, 4.2, 5.4],
'PetalWidth': [0.5, 1.5, 2.1],
}
predict_x = [[5.1, 5.9, 6.9],
[3.3, 3.0, 3.1],
[1.7, 4.2, 5.4],
[0.5, 1.5, 2.1]
]
predict_x = [[l[i] for l in predict_x] for i in range(3)]
# 由于训练的时候进行了batch,为了保证训练和测试的一致性,因此测试的时候也要batch
# 因为对于dataset来讲,batch前后存储的数据格式是不一样的
# 并且测试的时候,dataset里不需要label
# 训练集的dataset的格式是(dict:[string,1维array],),因为会batch
predictions = model.predict(
input_fn=lambda: tf.data.Dataset.from_tensor_slices(predict_x).batch(1))
template = ('\nPrediction is "{}" ({:.1f}%), expected "{}"')
for pred_dict, expec in zip(predictions, expected):
# class_id = pred_dict['class_ids'][0]
# probability = pred_dict['probabilities'][class_id]
#
# print(template.format(iris.SPECIES[class_id],
# 100 * probability, expec))
print(pred_dict)
print(expec)
train_eval_test2('data/iris/iris_training.csv', None, 100, 'data/iris/iris_training.csv')
Tensorflow中数据集的使用方法(tf.data.Dataset)
以iris_train,iris_test两个文件介绍TextlineDataset的用法
FIELD_DEFAULTS = [[0.0], [0.0], [0.0], [0.0], [0]]
def input_fn(file_path):
def _parse_line(line):
# 解析每个元素
fields = tf.decode_csv(line, FIELD_DEFAULTS)
# fields的类型是list,与设想的不同,这个函数只会被执行一次
# 你可以在这个地方打印一个东西,你会发现这个打印操作只进行了1次
return fields[:-1], fields[-1]
# 跳过一个元素
dataset = tf.data.TextLineDataset(file_path).skip(1)
dataset = dataset.map(_parse_line)
# 注意,filter函数里的接受参数数量一定要和dataset里的每个元素包括的元素数量一致
# 另外,判断相等的时候,一定要用tf.equal,因为实际上ab都是tensor,不能直接用==
dataset = dataset.filter(lambda a, b: tf.equal(b, 1))
#把下面的注释再打开看看结果有什么不同,体会一下
#dataset = dataset.batch(2)
return dataset
if __name__ == '__main__':
data = input_fn('data/iris/iris_test.csv')
iter = data.make_one_shot_iterator()
x = iter.get_next()
# x是(, )
# 也就是说x里有两个元素
print(x)
with tf.Session() as sess:
print(sess.run(x))
print(sess.run(x))
from_tensor_slices代码,第一个是以元组方式输入,第二个是以列表形式输入,第一个dataset的第一个元素就是元组中4个数字里的第一个数字(也就是4个1),而第二个dataset的第一个元素,就是[1,2]
features_dataset = tf.data.Dataset.from_tensor_slices(([1,2], [1,2], [1,2], [1,2]))
print(features_dataset)
features_dataset = tf.data.Dataset.from_tensor_slices([[1,2], [1,2], [1,2], [1,2]])
print(features_dataset)
TFRecordWriter
A tf.Operation that, when run, writes contents of dataset to a file.write方法返回的是一个op,需要run的,官方教程里用了tf.enable_eager_execution(),所以直接就执行了
注意dataset的迭代器的性质,下面两个session的结果是不一样的,每次run都相当于请求数据,每次请求的数据,只要用到了dataset中的数据,都会导致有数据流开始flow,所以第一个session才是正确的访问数据的方式,而第二个session,每次run都会导致get_next的执行
tf.reset_default_graph()
ds = tf.data.Dataset.from_tensor_slices([[1,2],[2,4],[3,6],[4,8],[5,10]])
ds=ds.map(lambda x:(x[0],x[1]))
i=ds.make_one_shot_iterator()
x,y=i.get_next()
a=tf.add(x,1)
b=tf.multiply(y,2)
with tf.Session() as sess:
try:
while True:
print(sess.run([x,y,a,b]))
except tf.errors.OutOfRangeError:
print('循环正常结束')
with tf.Session() as sess:
try:
while True:
print(sess.run([x,y]))
print(sess.run([a,b]))
except tf.errors.OutOfRangeError:
print('循环正常结束')
Tensorflow踩坑记之头疼的tf.data 各种iterator
以iris_train为例介绍用法
下面的程序演示了如何将一个文件转化成TFRecord文件,需要注意的是,tf.train.Feature,tf.train.Int64List,tf.train.Example对象构建的时候,他们的传入参数名称都不能省略,比如float_list=,int64_list=,features=等等,并且value=接的参数必须是可迭代对象,比如说列表,并且floatlist的存储方式是tf.float32
写入的时候tf.train.Features的feature参数存的是一个dict,key为特征名,value为Feature对象
下面这种方法是以python_io的方式来写入tf_rec文件
import tensorflow as tf
CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
'PetalLength', 'PetalWidth', 'Species']
SPECIES = ['Setosa', 'Versicolor', 'Virginica']
def _float_feature(value):
return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))
def _int64_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[int(value)]))
def convert_to_tf_record(file_path='data/iris/iris_training.csv', output_path='data/tf_record/iris_training.tfr'):
import pandas as pd
def feature_dict(row: pd.Series):
d = {CSV_COLUMN_NAMES[i]: _float_feature(row[i]) for i in range(4)}
d[CSV_COLUMN_NAMES[-1]] = _int64_feature(row[-1])
return d
iris = pd.read_csv(file_path, header=None, names=CSV_COLUMN_NAMES, skiprows=1)
with tf.python_io.TFRecordWriter(output_path) as writer:
for index, row in iris.iterrows():
example = tf.train.Example(features=tf.train.Features(feature=feature_dict(row)))
writer.write(example.SerializeToString())
writer.close()
过些阵子我补一个用dataset写tfrec文件的代码
以下是用dataset读取tfrecord文件的第一种方式,在这里,刚开始读取的dataset里,每个元素都是一个Example对象,并且通过map每次只对一个example进行解析,其中dataset的形状为DatasetV1Adapter shapes: (( ), ( ), (), (), ()), types: (tf.float32, tf.float32, tf.float32, tf.float32, tf.int64)
import tensorflow as tf
CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
'PetalLength', 'PetalWidth', 'Species']
def get_iris_tfrecord_dataset_with_single_parse(file_path='data/tf_record/iris_training.tfr'):
feature_dict = {CSV_COLUMN_NAMES[i]: tf.FixedLenFeature([], tf.float32) for i in range(4)}
feature_dict[CSV_COLUMN_NAMES[-1]] = tf.FixedLenFeature([], tf.int64)
def _parse(example):
features = tf.parse_single_example(example, features=feature_dict)
return [features[name] for name in CSV_COLUMN_NAMES]
dataset = tf.data.TFRecordDataset(file_path)
dataset = dataset.map(_parse)
print(dataset)
iter = dataset.make_one_shot_iterator()
x = iter.get_next()
with tf.Session() as sess:
print(sess.run(x))
print(sess.run(x))
return dataset
以下是用dataset读取tfrecord文件的第二种方式,在这里,刚开始读取的dataset里,每个元素都是一个Example对象,然后,先进行了batch操作,再通过map每次只对每个batch内的多个example进行解析,dataset的形状会变成DatasetV1Adapter shapes: ((?, ), ( ?,), (?, ), (?, ), (?, )), types: (tf.float32, tf.float32, tf.float32, tf.float32, tf.int64)
,也就是说,parse_example是对每个batch内所有example进行解析操作
import tensorflow as tf
CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
'PetalLength', 'PetalWidth', 'Species']
def get_iris_tfrecord_dataset_with_parse(file_path='data/tf_record/iris_training.tfr'):
feature_dict = {CSV_COLUMN_NAMES[i]: tf.FixedLenFeature([], tf.float32) for i in range(4)}
feature_dict[CSV_COLUMN_NAMES[-1]] = tf.FixedLenFeature([], tf.int64)
def _parse(example):
features = tf.parse_example(example, features=feature_dict)
return [features[name] for name in CSV_COLUMN_NAMES]
dataset = tf.data.TFRecordDataset(file_path)
dataset = dataset.batch(10)
dataset = dataset.map(_parse)
print(dataset)
iter = dataset.make_one_shot_iterator()
x = iter.get_next()
with tf.Session() as sess:
print(sess.run(x))
print(sess.run(x))
return dataset
从tfrecord文件解析的时候,需要指定features=这个参数,这个参数是一个dict,key为特征名,value为一个FixedLenFeature或者VarLenFeature,通过这两个东西,我们可以确定每个特征的形状以及类型
上一节,在第一种使用parse_single_example解析example的代码中,我使用了FixedLenFeature([], tf.float32),意思就是,某个特征,他的形状是[],这代表的是,该特征里存的就是一个数,并且是tf.float32类型的,你把这个FixedLenFeature([], tf.float32)换成FixedLenFeature([1], tf.float32),这样解析的时候,就会认为这个特征里存的是一个1维度长度为1的向量,重新跑第一个程序,dataset的变成DatasetV1Adapter shapes: ((1, ), (1, ), (1, ), (1, ), (1, )), types: (tf.float32, tf.float32, tf.float32, tf.float32, tf.int64)
Tensorflow高阶读写教程,中有提到,example里的一个特征里可以简单的存一个数,也可以存多个数,但这个特征里的多个值的类型一定要相同
但对于第二种使用parse_example解析example的代码中,FixedLenFeature([], tf.float32)换成FixedLenFeature([1], tf.float32),结果会不同,代码如下,dataset的形状同样会变成
,和之前的是一个道理
另外,在解析对象的时候,即使文件中的某个特征是int类型存的,读取的时候仍然可以按照float类型来解析,但反过来不行
import tensorflow as tf
CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
'PetalLength', 'PetalWidth', 'Species']
def get_iris_tfrecord_dataset_with_parse(file_path='data/tf_record/iris_training.tfr'):
feature_dict = {CSV_COLUMN_NAMES[i]: tf.FixedLenFeature([1], tf.float32) for i in range(4)}
feature_dict[CSV_COLUMN_NAMES[-1]] = tf.FixedLenFeature([1], tf.int64)
def _parse(example):
features = tf.parse_example(example, features=feature_dict)
return [features[name] for name in CSV_COLUMN_NAMES]
dataset = tf.data.TFRecordDataset(file_path)
dataset = dataset.batch(10)
dataset = dataset.map(_parse)
print(dataset)
iter = dataset.make_one_shot_iterator()
x = iter.get_next()
with tf.Session() as sess:
print(sess.run(x))
print(sess.run(x))
return dataset
下面的代码演示了,一个特征里存多个数的方法,如代码所示,一个example里只有一个名为data的特征,这个特征里存了两个数,那么读取的时候,就要指定data这个特征里的存的数字的数目是2
def multi_rank_convert_to_tf_record(output_path='data/tf_record/multirank.tfr'):
data = [[1,2],[3,4]]
with tf.python_io.TFRecordWriter(output_path) as writer:
for row in data:
example = tf.train.Example(features=tf.train.Features(feature={
'data':tf.train.Feature(int64_list=tf.train.Int64List(value=row))
}))
writer.write(example.SerializeToString())
writer.close()
def get_multi_rank_tf_dataset(file_path='data/tf_record/multirank.tfr'):
def _parse(example):
features = tf.parse_single_example(example,features={'data':tf.FixedLenFeature([2],tf.int64)})
return features
dataset = tf.data.TFRecordDataset(file_path)
dataset = dataset.map(_parse)
print(dataset)
iter = dataset.make_one_shot_iterator()
x = iter.get_next()
with tf.Session() as sess:
print(sess.run(x))
print(sess.run(x))
return dataset
顾名思义,就是变长特征,返回的是SparseTensorValue
def multi_rank_convert_to_tf_record(output_path='data/tf_record/multirank.tfr'):
# data = [[1,2],[3,4]]
data = [[1],[3,4,5]]
with tf.python_io.TFRecordWriter(output_path) as writer:
for row in data:
example = tf.train.Example(features=tf.train.Features(feature={
'data':tf.train.Feature(int64_list=tf.train.Int64List(value=row))
}))
writer.write(example.SerializeToString())
writer.close()
def get_multi_rank_tf_dataset(file_path='data/tf_record/multirank.tfr'):
def _parse(example):
# features = tf.parse_single_example(example,features={'data':tf.FixedLenFeature([2],tf.int64)})
features = tf.parse_single_example(example,features={'data':tf.VarLenFeature(tf.int64)})
return features
dataset = tf.data.TFRecordDataset(file_path)
dataset = dataset.map(_parse)
print(dataset)
iter = dataset.make_one_shot_iterator()
x = iter.get_next()
with tf.Session() as sess:
print(sess.run(x))
print(sess.run(x))
return dataset
TensorFlow中CNN的两种padding方式“SAME”和“VALID”
import tensorflow as tf
input = tf.ones([1, 5, 5, 1])
filter_weight = tf.Variable(tf.ones([3, 3, 1, 4]))
conv1 = tf.nn.conv2d(input, filter_weight, strides=[1, 1, 1, 1], padding='SAME')
conv2 = tf.nn.conv2d(input, filter_weight, strides=[1, 1, 1, 1], padding='VALID')
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(conv1))
print(sess.run(conv2))
你可以打印一下input是啥,这个input和我想象的不太一致,不过input[0,:,:,0]代表的就是第一个图片的第一个channal
conv1的输出和conv2不一样,SAME是因为补充零了,怎么补充的呢,你把input想象成一张55并且只有一个通道的图片,然后用一个33并且输出为4通道的filter卷积,print(sess.run(conv1)[0,:,:,0])就是这张图片的第一层输出,可以看到,在四周都进行了padding的补0操作
RNNCell使用
下面两个conv2d_layer是参数共享的
net = tf.Variable([[[[2.,3.]]]])
with tf.variable_scope('name') as scope:
conv2d_layer = tf.layers.Conv2D(2,[1,1])
out = conv2d_layer(net)
print(conv2d_layer.variables)
with tf.variable_scope('name',reuse=True) as scope:
conv2d_layer = tf.layers.Conv2D(2,[1,1])
out = conv2d_layer(net)
print(conv2d_layer.variables)
tf.contrib.slim简介
Slim下的函数介绍(一)
TensorFlow-slim 训练 CNN 分类模型
TensorFlow 使用预训练模型 ResNet-50
get_init_fn(checkpoint_exclude_scopes)是不恢复exclude里的变量
get_trainable_variables(scopes_to_freeze )是获取除了scopes_to_freeze包含的变量,送给minimize,就可以保证不更新scopes_to_freeze里的参数了
十图详解tensorflow数据读取机制(附代码)
Tensorflow–tf.FIFOQueue详解
tensorflow队列操作详解
下面这两段代码都会block,第一段是因为,用的是enqueue,每次入队只进一个元素,就是[3,2,1],后面的并没有入队。第二段是因为队列满了,enqueue被block了,所以后面的操作都进行不了
import tensorflow as tf
input_data=[[3.,2.,1.],[11.,22.,33.],[111.,222.,333.]]
q=tf.FIFOQueue(3,dtypes=[tf.float32])
init=q.enqueue(input_data)
output_data=q.dequeue()
with tf.Session() as sess:
init.run()
init.run()
print('1:',sess.run(output_data))
print('2:',sess.run(output_data))
print('3:',sess.run(output_data))
sess.run(q.close(cancel_pending_enqueues=True))
print(sess.run(q.is_closed()))
with tf.Session() as sess:
qr = tf.FIFOQueue(capacity=3, dtypes=[tf.uint8], shapes=((), ))
en_qr = qr.enqueue_many([[1, 2, 3,4,5,6]])
sess.run(en_qr)
de_qr = qr.dequeue()
res = sess.run(de_qr)
print(res)
de_qr = qr.dequeue()
res = sess.run(de_qr)
print(res)
import tensorflow as tf
if __name__ == '__main__':
with tf.Session() as sess:
qr = tf.FIFOQueue(capacity=6, dtypes=[tf.uint8], shapes=((),))
en_qr = qr.enqueue_many([[1, 2, 3, 4, 5, 6]])
sess.run(en_qr)
de_qr = qr.dequeue()
res = sess.run(de_qr)
print(res)
de_qr = qr.dequeue()
res = sess.run(de_qr)
print(res)
with tf.Session() as sess:
qr = tf.FIFOQueue(capacity=6, dtypes=[tf.uint8], shapes=((),))
en_qr = qr.enqueue([1])
sess.run(en_qr)
de_qr = qr.dequeue()
res = sess.run(de_qr)
print(res)
en_qr = qr.enqueue([2])
sess.run(en_qr)
de_qr = qr.dequeue()
res = sess.run(de_qr)
print(res)
tensorflow word2vec demo详解
一个快速完整的教程,以保存和恢复Tensorflow模型
import tensorflow as tf
# 代码1,储存模型
v1 = tf.Variable(tf.constant(2.0, shape=[1]), name='v1')
v2 = tf.Variable(tf.constant(2.0, shape=[1]), name='v2')
result = v1 + v2
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
saver.save(sess,'ckpt_dir/model.ckpt')
import tensorflow as tf
# 代码2 读取数据
v1 = tf.Variable(tf.constant(1.0, shape=[1]), name='v1')
v2 = tf.Variable(tf.constant(2.0, shape=[1]), name='v2')
result = v1 + v2
saver = tf.train.Saver()
with tf.Session() as sess:
saver.restore(sess, 'ckpt_dir/model.ckpt')
print(sess.run(v1))
print(sess.run(result))
# [2.]
# [4.]
下面代码如果把初始化放在restore后面,那么结果返回的就是1和3
import tensorflow as tf
# 代码3 读取只读取v1
v1 = tf.Variable(tf.constant(1.0, shape=[1]), name='v1')
v2 = tf.Variable(tf.constant(2.0, shape=[1]), name='v2')
result = v1 + v2
saver = tf.train.Saver([v1])
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
saver.restore(sess, 'ckpt_dir/model.ckpt')
print(sess.run(v1))
print(sess.run(result))
# [2.]
# [4.]
tensorflow 只恢复部分模型参数
浅谈Tensorflow模型的保存与恢复加载
我改了一下代码
restore的时候需要指定具体哪个model,所以latest_checkpoint这个方法就很好用了
#存储pb
import tensorflow as tf
import os
from tensorflow.python.framework import graph_util
pb_file_path = 'ckpt_dir/combined_model.pb'
x = tf.placeholder(tf.int32, shape=[1, 3], name='x')
weights = tf.Variable([[2], [2], [1]])
b = tf.Variable(1, name='b')
wx = tf.matmul(x, weights)
# 这里的输出需要加上name属性
op = tf.add(wx, b, name='op_to_store')
sess = tf.Session()
sess.run(tf.global_variables_initializer())
path = os.path.dirname(os.path.abspath(pb_file_path))
if os.path.isdir(path) is False:
os.makedirs(path)
# convert_variables_to_constants 需要指定output_node_names,list(),可以多个
constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph_def, ['op_to_store'])
with tf.gfile.FastGFile(pb_file_path, mode='wb') as f:
f.write(constant_graph.SerializeToString())
# test
feed_dict = {x: [[1, 2, 3]]}
print(sess.run(op, feed_dict))
#读取pb
import tensorflow as tf
from tensorflow.python.platform import gfile
def restore_mode_pb(pb_file_path):
sess = tf.Session()
with gfile.FastGFile(pb_file_path, 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
sess.graph.as_default()
tf.import_graph_def(graph_def, name='')
print(sess.run('b:0'))
input_x = sess.graph.get_tensor_by_name('x:0')
# input_y = sess.graph.get_tensor_by_name('y:0')
op = sess.graph.get_tensor_by_name('op_to_store:0')
ret = sess.run(op, {input_x: [[2,2,3]]})
print(ret)
restore_mode_pb('ckpt_dir/combined_model.pb')
tensorflow saver和checkpoint总结
draw_bounding_boxes
就是一个给图片上画框框的方法,bbox是一个[batch, num_bounding_boxes, 4]的张量,可以画num_bounding_boxes个框框,比如说下面代码,这个bbox就是画两个框框,但是我发现总有时候画不上去,我也不太懂咋回事
bbox = tf.constant([[[0.1, 0.35, 0.6, 0.75],[0.15, 0.3, 0.3, 0.4]]],
dtype=tf.float32,
shape=[1, 2, 4])
image_with_box = tf.image.draw_bounding_boxes(tf.expand_dims(image, 0),
bbox)
tf.image.sample_distorted_bounding_box
其实《google实战》那本书里有提到过这个方法,就是随机生成一个框框,至于bounding_boxes,讲得就是图片里哪些范围内是有信息量的,然后min_object_covered参数指的是The cropped area of the image must contain at least this fraction of any bounding box supplied.就是输出的框框至少应该包括百分之多少的bounding_boxes
tensorflow中的control_flow_ops.switch函数介绍
Tensorflow(4)-control_flow_ops.cond
How to use the function merge and switch of tensorflow?
深入学习图像处理——图像相似度算法——基于PILLOW
报错LossTensor is inf or nan
,网上说都是什么学习率太大了,梯度跑飞了,这个可以理解,但是我遇到这个问题,是因为用了tf.losses.sparse_softmax_cross_entropy(labels=label_batch, logits=out)
这个方法,在这个方法里,labels是标签,比如可以是[0,1,2],代表三个样本,第一个样本的类标签是0;logits就是输出的几率,比如说可以是[[0.5,0.4,0.1],[0.4,0.5,0.1],[0.2,0.2,0.6]]。(这个方法实际上就在调用tf.nn.sparse_softmax_cross_entropy_with_logits.
)
但是我为什么会报上面那个错呢,是因为样本类别的数目是456,就是从0到455,所以labels的输入的类标签就应该是0到455,但是我把输出层的神经元节点数目搞错了,输出层的神经元节点数目变成了455,也就是说,每个样本的logits的维度数目是455。而恰好我又是在GPU上跑的,官方文档对于labels这个参数有说明Tensor of shape [d_0, d_1, ..., d_{r-1}] (where r is rank of labels and result) and dtype int32 or int64. Each entry in labels must be an index in [0, num_classes). Other values will raise an exception when this op is run on CPU, and return NaN for corresponding loss and gradient rows on GPU.
,就是说如果labels和logits的类数目对应不上,在CPU上会报错,但是GPU上会导致返回值为NaN,所以就导致了上面的错误