操作 | 描述 |
---|---|
tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)* | 计算输入logits, targets的交叉熵 |
tf.nn.softmax(logits, name=None) | 计算softmaxsoftmax[i, j] = exp(logits[i, j]) / sum_j(exp(logits[i, j])) |
tf.nn.log_softmax(logits, name=None) | logsoftmax[i, j] = logits[i, j] - log(sum(exp(logits[i]))) |
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None) | 计算logits和labels的softmax交叉熵logits, labels必须为相同的shape与数据类型 |
tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels, name=None) | 计算logits和labels的softmax交叉熵 |
tf.nn.weighted_cross_entropy_with_logits(logits, targets, pos_weight, name=None) | 与sigmoid_cross_entropy_with_logits()相似,但给正向样本损失加了权重pos_weight |
- 符号嵌入(Embeddings)
操作 | 描述 |
---|---|
tf.nn.embedding_lookup(params, ids, partition_strategy=’mod’, name=None, validate_indices=True) | 根据索引ids查询embedding列表params中的tensor值如果len(params) > 1,id将会安照partition_strategy策略进行分割1、如果partition_strategy为”mod”,id所分配到的位置为p = id % len(params)比如有13个ids,分为5个位置,那么分配方案为:[[0, 5, 10], [1, 6, 11], [2, 7, 12], [3, 8], [4, 9]]2、如果partition_strategy为”div”,那么分配方案为:[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10], [11, 12]] |
tf.nn.embedding_lookup_sparse(params, sp_ids, sp_weights, partition_strategy=’mod’, name=None, combiner=’mean’) | 对给定的ids和权重查询embedding1、sp_ids为一个N x M的稀疏tensor,N为batch大小,M为任意,数据类型int642、sp_weights的shape与sp_ids的稀疏tensor权重,浮点类型,若为None,则权重为全’1’ |
- 循环神经网络(Recurrent Neural Networks)
操作 | 描述 |
---|---|
tf.nn.rnn(cell, inputs, initial_state=None, dtype=None, sequence_length=None, scope=None) | 基于RNNCell类的实例cell建立循环神经网络 |
tf.nn.dynamic_rnn(cell, inputs, sequence_length=None, initial_state=None, dtype=None, parallel_iterations=None, swap_memory=False, time_major=False, scope=None) | 基于RNNCell类的实例cell建立动态循环神经网络与一般rnn不同的是,该函数会根据输入动态展开返回(outputs,state) |
tf.nn.state_saving_rnn(cell, inputs, state_saver, state_name, sequence_length=None, scope=None) | 可储存调试状态的RNN网络 |
tf.nn.bidirectional_rnn(cell_fw, cell_bw, inputs, initial_state_fw=None, initial_state_bw=None, dtype=None,sequence_length=None, scope=None) | 双向RNN, 返回一个3元组tuple(outputs, output_state_fw, output_state_bw) |
— tf.nn.rnn简要介绍—
cell: 一个RNNCell实例
inputs: 一个shape为[batch_size, input_size]的tensor
initial_state: 为RNN的state设定初值,可选
sequence_length:制定输入的每一个序列的长度,size为[batch_size],值范围为[0, T)的int型数据
其中T为输入数据序列的长度
@
@针对输入batch中序列长度不同,所设置的动态计算机制
@对于在时间t,和batch的b行,有
(output, state)(b, t) = ? (zeros(cell.output_size), states(b, sequence_length(b) - 1)) : cell(input(b, t), state(b, t - 1))
- 求值网络(Evaluation)
操作 | 描述 |
---|---|
tf.nn.top_k(input, k=1, sorted=True, name=None) | 返回前k大的值及其对应的索引 |
tf.nn.in_top_k(predictions, targets, k, name=None) | 返回判断是否targets索引的predictions相应的值是否在在predictions前k个位置中,返回数据类型为bool类型,len与predictions同 |
对于有巨大量的多分类与多标签模型,如果使用全连接softmax将会占用大量的时间与空间资源,所以采用候选采样方法仅使用一小部分类别与标签作为监督以加速训练。
操作 | 描述 |
---|---|
Sampled Loss Functions | |
tf.nn.nce_loss(weights, biases, inputs, labels, num_sampled,num_classes, num_true=1, sampled_values=None,remove_accidental_hits=False, partition_strategy=’mod’,name=’nce_loss’) | 返回noise-contrastive的训练损失结果 |
tf.nn.sampled_softmax_loss(weights, biases, inputs, labels, num_sampled, num_classes, num_true=1, sampled_values=None,remove_accidental_hits=True, partition_strategy=’mod’, name=’sampled_softmax_loss’) | 返回sampled softmax的训练损失参考- Jean et al., 2014第3部分 |
Candidate Samplers | |
tf.nn.uniform_candidate_sampler(true_classes, num_true, num_sampled, unique, range_max, seed=None, name=None) | 通过均匀分布的采样集合返回三元tuple1、sampled_candidates 候选集合。2、期望的true_classes个数,为浮点值3、期望的sampled_candidates个数,为浮点值 |
tf.nn.log_uniform_candidate_sampler(true_classes, num_true,num_sampled, unique, range_max, seed=None, name=None) | 通过log均匀分布的采样集合,返回三元tuple |
tf.nn.learned_unigram_candidate_sampler(true_classes, num_true, num_sampled, unique, range_max, seed=None, name=None) | 根据在训练过程中学习到的分布状况进行采样返回三元tuple |
tf.nn.fixed_unigram_candidate_sampler(true_classes, num_true,num_sampled, unique, range_max, vocab_file=”, distortion=1.0, num_reserved_ids=0, num_shards=1, shard=0, unigrams=(), seed=None, name=None) | 基于所提供的基本分布进行采样 |
保存与恢复变量
操作 | 描述 |
---|---|
类tf.train.Saver(Saving and Restoring Variables) | |
tf.train.Saver.__init__(var_list=None, reshape=False, sharded=False, max_to_keep=5, keep_checkpoint_every_n_hours=10000.0, name=None, restore_sequentially=False,saver_def=None, builder=None) | 创建一个存储器Savervar_list定义需要存储和恢复的变量 |
tf.train.Saver.save(sess, save_path, global_step=None, latest_filename=None, meta_graph_suffix=’meta’,write_meta_graph=True) | 保存变量 |
tf.train.Saver.restore(sess, save_path) | 恢复变量 |
tf.train.Saver.last_checkpoints | 列出最近未删除的checkpoint 文件名 |
tf.train.Saver.set_last_checkpoints(last_checkpoints) | 设置checkpoint文件名列表 |
tf.train.Saver.set_last_checkpoints_with_time(last_checkpoints_with_time) | 设置checkpoint文件名列表和时间戳 |
第二部分
1、tensorflow的基本运作
为了快速的熟悉TensorFlow编程,下面从一段简单的代码开始:
import tensorflow as tf
#定义‘符号’变量,也称为占位符
a = tf.placeholder("float")
b = tf.placeholder("float")
y = tf.mul(a, b) #构造一个op节点
sess = tf.Session()#建立会话
#运行会话,输入数据,并计算节点,同时打印结果
print sess.run(y, feed_dict={a: 3, b: 3})
# 任务完成, 关闭会话.
sess.close()
其中tf.mul(a, b)函数便是tf的一个基本的算数运算,接下来介绍跟多的相关函数。
2、tf函数
TensorFlow 将图形定义转换成分布式执行的操作, 以充分利用可用的计算资源(如 CPU 或 GPU。一般你不需要显式指定使用 CPU 还是 GPU, TensorFlow 能自动检测。如果检测到 GPU, TensorFlow 会尽可能地利用找到的第一个 GPU 来执行操作.
并行计算能让代价大的算法计算加速执行,TensorFlow也在实现上对复杂操作进行了有效的改进。大部分核相关的操作都是设备相关的实现,比如GPU。本文主要涉及的相关概念或操作有以下内容:
操作组 | 操作 |
---|---|
Building Graphs | Core graph data structures,Tensor types,Utility functions |
Inputs and Readers | Placeholders,Readers,Converting,Queues,Input pipeline |
2.1 建立图(Building Graphs)
本节主要介绍建立tensorflow图的相关类或函数
* 核心图的数据结构(Core graph data structures)
tf.Graph
操作 | 描述 |
---|---|
class tf.Graph | tensorflow中的计算以图数据流的方式表示一个图包含一系列表示计算单元的操作对象以及在图中流动的数据单元以tensor对象表现 |
tf.Graph.__init__() | 建立一个空图 |
tf.Graph.as_default() | 一个将某图设置为默认图,并返回一个上下文管理器如果不显式添加一个默认图,系统会自动设置一个全局的默认图。所设置的默认图,在模块范围内所定义的节点都将默认加入默认图中 |
tf.Graph.as_graph_def(from_version=None, add_shapes=False) | 返回一个图的序列化的GraphDef表示序列化的GraphDef可以导入至另一个图中(使用 import_graph_def())或者使用C++ Session API |
tf.Graph.finalize() | 完成图的构建,即将其设置为只读模式 |
tf.Graph.finalized | 返回True,如果图被完成 |
tf.Graph.control_dependencies(control_inputs) | 定义一个控制依赖,并返回一个上下文管理器with g.control_dependencies([a, b, c]):# d 和 e 将在 a , b , 和c 执行完之后运行.d = …e = … |
tf.Graph.device(device_name_or_function) | 定义运行图所使用的设备,并返回一个上下文管理器with g.device('/gpu:0'): ...``with g.device('/cpu:0'): ... |
tf.Graph.name_scope(name) | 为节点创建层次化的名称,并返回一个上下文管理器 |
tf.Graph.add_to_collection(name, value) | 将value以name的名称存储在收集器(collection)中 |
tf.Graph.get_collection(name, scope=None) | 根据name返回一个收集器中所收集的值的列表 |
tf.Graph.as_graph_element(obj, allow_tensor=True, allow_operation=True) | 返回一个图中与obj相关联的对象,为一个操作节点或者tensor数据 |
tf.Graph.get_operation_by_name(name) | 根据名称返回操作节点 |
tf.Graph.get_tensor_by_name(name) | 根据名称返回tensor数据 |
tf.Graph.get_operations() | 返回图中的操作节点列表 |
tf.Graph.gradient_override_map(op_type_map) | 用于覆盖梯度函数的上下文管理器 |
#class tf.Graph
#tensorflow运行时需要设置默认的图
g = tf.Graph()
with g.as_default():
# Define operations and tensors in `g`.
c = tf.constant(30.0)
assert c.graph is g
##也可以使用tf.get\_default\_graph()获得默认图,也可在基础上加入节点或子图
c = tf.constant(4.0)
assert c.graph is tf.get_default_graph()
#tf.Graph.as\_default
#以下两段代码功能相同
#1、使用Graph.as\_default():
g = tf.Graph()
with g.as_default():
c = tf.constant(5.0)
assert c.graph is g
#2、构造和设置为默认
with tf.Graph().as_default() as g:
c = tf.constant(5.0)
assert c.graph is g
#tf.Graph.control\_dependencies(control\_inputs)
# 错误代码
def my\_func(pred, tensor):
t = tf.matmul(tensor, tensor)
with tf.control_dependencies([pred]):
# 乘法操作(op)没有创建在该上下文,所以没有被加入依赖控制
return t
# 正确代码
def my\_func(pred, tensor):
with tf.control_dependencies([pred]):
# 乘法操作(op)创建在该上下文,所以被加入依赖控制中
#执行完pred之后再执行matmul
return tf.matmul(tensor, tensor)
# tf.Graph.name\_scope(name)
# 一个图中包含有一个名称范围的堆栈,在使用name\_scope(...)之后,将压(push)新名称进栈中,
#并在下文中使用该名称
with tf.Graph().as_default() as g:
c = tf.constant(5.0, name="c")
assert c.op.name == "c"
c_1 = tf.constant(6.0, name="c")
assert c_1.op.name == "c\_1"
# Creates a scope called "nested"
with g.name_scope("nested") as scope:
nested_c = tf.constant(10.0, name="c")
assert nested_c.op.name == "nested/c"
# Creates a nested scope called "inner".
with g.name_scope("inner"):
nested_inner_c = tf.constant(20.0, name="c")
assert nested_inner_c.op.name == "nested/inner/c"
# Create a nested scope called "inner\_1".
with g.name_scope("inner"):
nested_inner_1_c = tf.constant(30.0, name="c")
assert nested_inner_1_c.op.name == "nested/inner\_1/c"
# Treats `scope` as an absolute name scope, and
# switches to the "nested/" scope.
with g.name_scope(scope):
nested_d = tf.constant(40.0, name="d")
assert nested_d.op.name == "nested/d"
with g.name_scope(""):
e = tf.constant(50.0, name="e")
assert e.op.name == "e"
tf.Operation
操作 | 描述 |
---|---|
class tf.Operation | 代表图中的一个节点,用于计算tensors数据该类型将由python节点构造器产生(比如tf.matmul())或者Graph.create_op()例如c = tf.matmul(a, b)创建一个Operation类为类型为”MatMul”,输入为’a’,’b’,输出为’c’的操作类 |
tf.Operation.name | 操作节点(op)的名称 |
tf.Operation.type | 操作节点(op)的类型,比如”MatMul” |
tf.Operation.inputstf.Operation.outputs | 操作节点的输入与输出 |
tf.Operation.control_inputs | 操作节点的依赖 |
tf.Operation.run(feed_dict=None, session=None) | 在会话(Session)中运行该操作 |
tf.Operation.get_attr(name) | 获取op的属性值 |
tf.Tensor
操作 | 描述 |
---|---|
class tf.Tensor | 表示一个由操作节点op产生的值,TensorFlow程序使用tensor数据结构来代表所有的数据, 计算图中, 操作间传递的数据都是 tensor,一个tensor是一个符号handle,里面并没有表示实际数据,而相当于数据流的载体 |
tf.Tensor.dtype | tensor中数据类型 |
tf.Tensor.name | 该tensor名称 |
tf.Tensor.value_index | 该tensor输出外op的index |
tf.Tensor.graph | 该tensor所处在的图 |
tf.Tensor.op | 产生该tensor的op |
tf.Tensor.consumers() | 返回使用该tensor的op列表 |
tf.Tensor.eval(feed_dict=None, session=None) | 在会话中求tensor的值需要使用with sess.as_default() 或者 eval(session=sess) |
tf.Tensor.get_shape() | 返回用于表示tensor的shape的类TensorShape |
tf.Tensor.set_shape(shape) | 更新tensor的shape |
tf.Tensor.device | 设置计算该tensor的设备 |
#tf.Tensor.get\_shape()
c = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print(c.get_shape())
==> TensorShape([Dimension(2), Dimension(3)])
#现在有个用于图像处理的tensor->image
print(image.get_shape())
==> TensorShape([Dimension(None), Dimension(None), Dimension(3)])
# 假如我们知道数据集中图像尺寸为28 x 28,那么可以设置
image.set_shape([28, 28, 3])
print(image.get_shape())
==> TensorShape([Dimension(28), Dimension(28), Dimension(3)])
* tensor类型(Tensor types)
tf.DType
操作 | 描述 |
---|---|
class tf.DType | 数据类型主要包含tf.float16,tf.float16,tf.float32,tf.float64,tf.bfloat16,tf.complex64,tf.complex128,tf.int8,tf.uint8,tf.uint16,tf.int16,tf.int32,tf.int64,tf.bool,tf.string |
tf.DType.is_compatible_with(other) | 判断other的数据类型是否将转变为该DType |
tf.DType.name | 数据类型名称 |
tf.DType.base_dtype | 返回该DType的基础DType,而非参考的数据类型(non-reference) |
tf.DType.as_ref | 返回一个基于DType的参考数据类型 |
tf.DType.is_floating | 判断是否为浮点类型 |
tf.DType.is_complex | 判断是否为复数 |
tf.DType.is_integer | 判断是否为整数 |
tf.DType.is_unsigned | 判断是否为无符号型数据 |
tf.DType.as_numpy_dtype | 返回一个基于DType的numpy.dtype类型 |
tf.DType.maxtf.DType.min | 返回这种数据类型能表示的最大值及其最小值 |
tf.as_dtype(type_value) | 返回由type_value转变得的相应tf数据类型 |
* 通用函数(Utility functions)
操作 | 描述 |
---|---|
tf.device(device_name_or_function) | 基于默认的图,其功能便为Graph.device() |
tf.container(container_name) | 基于默认的图,其功能便为Graph.container() |
tf.name_scope(name) | 基于默认的图,其功能便为 Graph.name_scope() |
tf.control_dependencies(control_inputs) | 基于默认的图,其功能便为Graph.control_dependencies() |
tf.convert_to_tensor(value, dtype=None, name=None, as_ref=False) | 将value转变为tensor数据类型 |
tf.get_default_graph() | 返回返回当前线程的默认图 |
tf.reset_default_graph() | 清除默认图的堆栈,并设置全局图为默认图 |
tf.import_graph_def(graph_def, input_map=None,return_elements=None, name=None, op_dict=None,producer_op_list=None) | 将graph_def的图导入到python中 |
* 图收集(Graph collections)
操作 | 描述 |
---|---|
tf.add_to_collection(name, value) | 基于默认的图,其功能便为Graph.add_to_collection() |
tf.get_collection(key, scope=None) | 基于默认的图,其功能便为Graph.get_collection() |
* 定义新操作节点(Defining new operations)
tf.RegisterGradient
操作 | 描述 |
---|---|
class tf.RegisterGradient | 返回一个用于寄存op类型的梯度函数的装饰器 |
tf.NoGradient(op_type) | 设置操作节点类型op_type的节点没有指定的梯度 |
class tf.RegisterShape | 返回一个用于寄存op类型的shape函数的装饰器 |
class tf.TensorShape | 表示tensor的shape |
tf.TensorShape.merge_with(other) | 与other合并shape信息,返回一个TensorShape类 |
tf.TensorShape.concatenate(other) | 与other的维度相连结 |
tf.TensorShape.ndims | 返回tensor的rank |
tf.TensorShape.dims | 返回tensor的维度 |
tf.TensorShape.as_list() | 以list的形式返回tensor的shape |
tf.TensorShape.is_compatible_with(other) | 判断shape是否为兼容TensorShape(None)与其他任何shape值兼容 |
class tf.Dimension | |
tf.Dimension.is_compatible_with(other) | 判断dims是否为兼容 |
tf.Dimension.merge_with(other) | 与other合并dims信息 |
tf.op_scope(values, name, default_name=None) | 在python定义op时,返回一个上下文管理器 |
#tf.RegisterGradient
#该装饰器只使用于定义一个新的op类型时候,如果一个op有m个输入,n个输出。那么该梯度函数应该设置原始的
#操作类型,以及n个Tensor对象(表示每一个op输出的梯度),以及m个对象(表示每一个op输入的偏梯度)
#以操作节点类型为'Sub'为例,两输入为x,y。为一个输出x-y
@tf.RegisterGradient("Sub")
def \_sub\_grad(unused\_op, grad):
return grad, tf.neg(grad)
#tf.op\_scope
#定义一个名称为my\_op的python操作节点op
def my\_op(a, b, c, name=None):
with tf.op_scope([a, b, c], name, "MyOp") as scope:
a = tf.convert_to_tensor(a, name="a")
b = tf.convert_to_tensor(b, name="b")
c = tf.convert_to_tensor(c, name="c")
# Define some computation that uses `a`, `b`, and `c`.
return foo_op(..., name=scope)
2.2 输入和读取器(Inputs and Readers)
本节主要介绍tensorflow中数据的读入相关类或函数
* 占位符(Placeholders)
tf提供一种占位符操作,在执行时需要为其提供数据data。
操作 | 描述 |
---|---|
tf.placeholder(dtype, shape=None, name=None) | 为一个tensor插入一个占位符eg:x = tf.placeholder(tf.float32, shape=(1024, 1024)) |
tf.placeholder_with_default(input, shape, name=None) | 当输出没有fed时,input通过一个占位符op |
tf.sparse_placeholder(dtype, shape=None, name=None) | 为一个稀疏tensor插入一个占位符 |
* 读取器(Readers)
tf提供一系列读取各种数据格式的类。对于多文件输入,可以使用函数tf.train.string_input_producer,该函数将创建一个保持文件的FIFO队列,以供reader使用。或者如果输入的这些文件名有相雷同的字符串,也可以使用函数tf.train.match_filenames_once。
操作 | 描述 |
---|---|
class tf.ReaderBase | 不同的读取器类型的基本类 |
tf.ReaderBase.read(queue, name=None) | 返回下一个记录对(key, value),queue为tf文件队列FIFOQueue |
tf.ReaderBase.read_up_to(queue, num_records, name=None) | 返回reader产生的num_records对(key, value) |
tf.ReaderBase.reader_ref | 返回应用在该reader上的Op |
tf.ReaderBase.reset(name=None) | 恢复reader为初始状态 |
tf.ReaderBase.restore_state(state, name=None) | 恢复reader为之前的保存状态state |
tf.ReaderBase.serialize_state(name=None) | 返回一个reader解码后产生的字符串tansor |
class tf.TextLineReader | |
tf.TextLineReader.num_records_produced(name=None) | 返回reader已经产生的记录(records )数目 |
tf.TextLineReader.num_work_units_completed(name=None) | 返回该reader已经完成的处理的work数目 |
tf.TextLineReader.read(queue, name=None) | 返回reader所产生的下一个记录对 (key, value),该reader可以限定新产生输出的行数 |
tf.TextLineReader.reader_ref | 返回应用在该reader上的Op |
tf.TextLineReader.reset(name=None) | 恢复reader为初始状态 |
tf.TextLineReader.restore_state(state, name=None) | 恢复reader为之前的保存状态state |
tf.TextLineReader.serialize_state(name=None) | 返回一个reader解码后产生的字符串tansor |
class tf.WholeFileReader | 一个阅读器,读取整个文件,返回文件名称key,以及文件中所有的内容value,该类的方法同上,不赘述 |
class tf.IdentityReader | 一个reader,以key和value的形式,输出一个work队列。该类其他方法基本同上 |
class tf.TFRecordReader | 读取TFRecord格式文件的reader。该类其他方法基本同上 |
class tf.FixedLengthRecordReader | 输出 |
* 数据转换(Converting)
tf提供一系列方法将各种格式数据转换为tensor表示。
操作 | 描述 |
---|---|
tf.decode_csv(records, record_defaults, field_delim=None, name=None) | 将csv转换为tensor,与tf.TextLineReader搭配使用 |
tf.decode_raw(bytes, out_type, little_endian=None, name=None) | 将bytes转换为一个数字向量表示,bytes为一个字符串类型的tensor与函数 tf.FixedLengthRecordReader搭配使用,详见tf的CIFAR-10例子 |
选取与要输入的文件格式相匹配的reader,并将文件队列提供给reader的读方法( read method)。读方法将返回文件唯一标识的key,以及一个记录(record)(有助于对出现一些另类的records时debug),以及一个标量的字符串值。再使用一个(或多个)解码器(decoder) 或转换操作(conversion ops)将字符串转换为tensor类型。
#读取文件队列,使用reader中read的方法,返回key与value
filename_queue = tf.train.string_input_producer(["file0.csv", "file1.csv"])
reader = tf.TextLineReader()
key, value = reader.read(filename_queue)
record_defaults = [[1], [1], [1], [1], [1]]
col1, col2, col3, col4, col5 = tf.decode_csv(
value, record_defaults=record_defaults)
features = tf.pack([col1, col2, col3, col4])
with tf.Session() as sess:
# Start populating the filename queue.
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
for i in range(1200):
# Retrieve a single instance:
example, label = sess.run([features, col5])
coord.request_stop()
coord.join(threads)
* Example protocol buffer
提供了一些Example protocol buffers,tf所推荐的用于训练样本的数据格式,它们包含特征信息,详情可见。
这是一种与前述将手上现有的各种数据类型转换为支持的格式的方法,这种方法更容易将网络结构与数据集融合或匹配。这种tensorflow所推荐的数据格式是一个包含tf.train.Example protocol buffers (包含特征Features域)的TFRecords文件。
1、获取这种格式的文件方式为,首先将一般的数据格式填入Example protocol buffer中,再将 protocol buffer序列化为一个字符串,然后使用tf.python_io.TFRecordWriter类的相关方法将字符串写入一个TFRecords文件中,参见MNIST例子,将MNIST 数据转换为该类型数据。
2、读取TFRecords格式文件的方法为,使用tf.TFRecordReader读取器和tf.parse_single_example解码器。parse_single_example操作将 example protocol buffers解码为tensor形式。参见MNIST例子
操作 | 描述 |
---|---|
class tf.VarLenFeature | 解析变长的输入特征feature相关配置 |
class tf.FixedLenFeature | 解析定长的输入特征feature相关配置 |
class tf.FixedLenSequenceFeature | 序列项目中的稠密(dense )输入特征的相关配置 |
tf.parse_example(serialized, features, name=None, example_names=None) | 将一组Example protos解析为tensor的字典形式解析serialized所给予的序列化的一些Example protos返回一个由特征keys映射Tensor和SparseTensor值的字典 |
tf.parse_single_example(serialized, features, name=None, example_names=None) | 解析一个单独的Example proto,与tf.parse_example方法雷同 |
tf.decode_json_example(json_examples, name=None) | 将JSON编码的样本记录转换为二进制protocol buffer字符串 |
#tf.parse\_example的使用举例
#输入序列化数据如下:
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] } } }
]
#那么输出为一个字典(dict),如下:
{"ft": SparseTensor(indices=[[0, 0], [0, 1], [2, 0]],
values=[1.0, 2.0, 3.0],
shape=(3, 2)) }
#########
#再来看一个例子,给定两个序列化的原始输入样本:
[
features {
feature { key: "kw" value { bytes_list { value: [ "knit", "big" ] } } }
feature { key: "gps" value { float_list { value: [] } } }
},
features {
feature { key: "kw" value { bytes_list { value: [ "emmy" ] } } }
feature { key: "dank" value { int64_list { value: [ 42 ] } } }
feature { key: "gps" value { } }
}
]
#相关参数如下:
example_names: ["input0", "input1"],
features: {
"kw": VarLenFeature(tf.string),
"dank": VarLenFeature(tf.int64),
"gps": VarLenFeature(tf.float32),
}
#那么有如下输出:
{
"kw": SparseTensor(
indices=[[0, 0], [0, 1], [1, 0]],
values=["knit", "big", "emmy"]
shape=[2, 2]),
"dank": SparseTensor(
indices=[[1, 0]],
values=[42],
shape=[2, 1]),
"gps": SparseTensor(
indices=[],
values=[],
shape=[2, 0]),
}
#########
#对于两个样本的输出稠密结果情况
[
features {
feature { key: "age" value { int64_list { value: [ 0 ] } } }
feature { key: "gender" value { bytes_list { value: [ "f" ] } } }
},
features {
feature { key: "age" value { int64_list { value: [] } } }
feature { key: "gender" value { bytes_list { value: [ "f" ] } } }
}
]
#我们可以使用以下参数
example_names: ["input0", "input1"],
features: {
"age": FixedLenFeature([], dtype=tf.int64, default_value=-1),
"gender": FixedLenFeature([], dtype=tf.string),
}
#期望的结果如下
{
"age": [[0], [-1]],
"gender": [["f"], ["f"]],
}
##Example protocol buffer相关使用的例子
#将mnist的数据转换为TFRecords文件格式
import os
import tensorflow as tf
from tensorflow.contrib.learn.python.learn.datasets import mnist
SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/'
TRAIN_IMAGES = 'train-images-idx3-ubyte.gz' # MNIST filenames
TRAIN_LABELS = 'train-labels-idx1-ubyte.gz'
TEST_IMAGES = 't10k-images-idx3-ubyte.gz'
TEST_LABELS = 't10k-labels-idx1-ubyte.gz'
tf.app.flags.DEFINE_string('directory', '/tmp/data',
'Directory to download data files and write the '
'converted result')
tf.app.flags.DEFINE_integer('validation\_size', 5000,
'Number of examples to separate from the training '
'data for the validation set.')
FLAGS = tf.app.flags.FLAGS
def \_int64\_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def \_bytes\_feature(value):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def convert\_to(data\_set, name):
images = data_set.images
labels = data_set.labels
num_examples = data_set.num_examples
if images.shape[0] != num_examples:
raise ValueError('Images size %d does not match label size %d.' %
(images.shape[0], num_examples))
rows = images.shape[1]
cols = images.shape[2]
depth = images.shape[3]
filename = os.path.join(FLAGS.directory, name + '.tfrecords')
print('Writing', filename)
writer = tf.python_io.TFRecordWriter(filename)
for index in range(num_examples):
image_raw = images[index].tostring()
example = tf.train.Example(features=tf.train.Features(feature={
'height': _int64_feature(rows),
'width': _int64_feature(cols),
'depth': _int64_feature(depth),
'label': _int64_feature(int(labels[index])),
'image\_raw': _bytes_feature(image_raw)}))
writer.write(example.SerializeToString())
writer.close()
def main(argv):
# Get the data.
data_sets = mnist.read_data_sets(FLAGS.directory,
dtype=tf.uint8,
reshape=False)
# Convert to Examples and write the result to TFRecords.
convert_to(data_sets.train, 'train')
convert_to(data_sets.validation, 'validation')
convert_to(data_sets.test, 'test')
if __name__ == '\_\_main\_\_':
tf.app.run()
* 队列(Queues)
tensorflow提供了几个队列应用,用来将tf计算图与tensors的阶段流水组织到一起。队列是使用tensorflow计算的一个强大的机制,正如其他Tensorflow的元素一样,一个队列也是tf图中的一个节点(node),它是一个有状态的node,就像一个变量:其他节点可以改变其内容。
我们来看一个简单的例子,如下gif图,我们将创建一个先入先出队列(FIFOQueue)并且将值全设为0,然后我们构建一个图以获取队列出来的元素,对该元素加1操作,并将结果再放入队列末尾。渐渐地,队列中的数字便增加。
操作 | 描述 |
---|---|
class tf.QueueBase | 基本的队列应用类.队列(queue)是一种数据结构,该结构通过多个步骤存储tensors,并且对tensors进行入列(enqueue)与出列(dequeue)操作 |
tf.QueueBase.enqueue(vals, name=None) | 将一个元素编入该队列中。如果在执行该操作时队列已满,那么将会阻塞直到元素编入队列之中 |
tf.QueueBase.enqueue_many(vals, name=None) | 将零个或多个元素编入该队列中 |
tf.QueueBase.dequeue(name=None) | 将元素从队列中移出。如果在执行该操作时队列已空,那么将会阻塞直到元素出列,返回出列的tensors的tuple |
tf.QueueBase.dequeue_many(n, name=None) | 将一个或多个元素从队列中移出 |
tf.QueueBase.size(name=None) | 计算队列中的元素个数 |
tf.QueueBase.close(cancel_pending_enqueues=False, name=None) | 关闭该队列 |
f.QueueBase.dequeue_up_to(n, name=None) | 从该队列中移出n个元素并将之连接 |
tf.QueueBase.dtypes | 列出组成元素的数据类型 |
tf.QueueBase.from_list(index, queues) | 根据queues[index]的参考队列创建一个队列 |
tf.QueueBase.name | 返回最队列下面元素的名称 |
tf.QueueBase.names | 返回队列每一个组成部分的名称 |
class tf.FIFOQueue | 在出列时依照先入先出顺序,其他方法与tf.QueueBase雷同 |
class tf.PaddingFIFOQueue | 一个FIFOQueue ,同时根据padding支持batching变长的tensor |
class tf.RandomShuffleQueue | 该队列将随机元素出列,其他方法与tf.QueueBase雷同 |
* 文件系统的处理(Dealing with the filesystem)
操作 | 描述 |
---|---|
tf.matching_files(pattern, name=None) | 返回与pattern匹配模式的文件名称 |
tf.read_file(filename, name=None) | 读取并输出输入文件的整个内容 |
* 输入管道(Input pipeline)
用于设置输入预取数的管道TF函数,函数 “producer”添加一个队列至图中,同时一个相应用于运行队列中子图(subgraph)的QueueRunner
操作 | 描述 |
---|---|
tf.train.match_filenames_once(pattern, name=None) | 保存与pattern的文件列表 |
tf.train.limit_epochs(tensor, num_epochs=None, name=None) | 返回一个num_epochs次数,然后报告OutOfRange错误 |
tf.train.input_producer(input_tensor, element_shape=None, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, summary_name=None, name=None) | 为一个输入管道输出input_tensor中的多行至一个队列中 |
tf.train.range_input_producer(limit, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None) | 产生一个从1至limit-1的整数至队列中 |
tf.train.slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None) | 对tensor_list中的每一个tensor切片 |
tf.train.string_input_producer(string_tensor, num_epochs=None,shuffle=True, seed=None, capacity=32, shared_name=None, name=None) | 为一个输入管道输出一组字符串(比如文件名)至队列中 |
* 在输入管道末端批量打包(Batching at the end of an input pipeline)
该相关函数增添一个队列至图中以将数据一样本打包为batch。它们也会添加 一个QueueRunner,以便执行的已经被填满队列的子图
操作 | 描述 |
---|---|
tf.train.batch(tensors, batch_size, num_threads=1,capacity=32, enqueue_many=False, shapes=None, dynamic_pad=False, allow_smaller_final_batch=False, shared_name=None, name=None) | 在输入的tensors中创建一些tensor数据格式的batch,若输入为shape[*, x, y, z],那么输出则为[batch_size, x, y, z]返回一个列表或者一个具有与输入tensors相同类型tensors的字典 |
tf.train.batch_join(tensors_list, batch_size, capacity=32, enqueue_many=False, shapes=None, dynamic_pad=False, allow_smaller_final_batch=False, shared_name=None, name=None) | 将一个tensors的列表添加至一个队列中以创建样本的batcheslen(tensors_list)个线程将启动,线程i将tensors_list[i]的tensors入列tensors_list[i1][j]与tensors_list[i2][j]有相同的类型和shape |
tf.train.shuffle_batch(tensors, batch_size, capacity, min_after_dequeue, num_threads=1, seed=None, enqueue_many=False, shapes=None, allow_smaller_final_batch=False,shared_name=None, name=None) | 使用随机乱序的方法创建batchestensors:用于入列的一个list或者dictcapacity:一个整数,表示队列中元素最大数目 |
tf.train.shuffle_batch_join(tensors_list, batch_size, capacity, min_after_dequeue, seed=None, enqueue_many=False, shapes=None, allow_smaller_final_batch=False, shared_name=None, name=None) | 随机乱序的tensors创建batches,其中tensors_list参数为tensors元组或tensors字典的列表len(tensors_list)个线程将启动,线程i将tensors_list[i]的tensors入列tensors_list[i1][j]与tensors_list[i2][j]有相同的类型和shape |
# 一个简单例子,使用tf.train.shuffle\_batch创建一个具有32张图像和32个标签的batches.
image_batch, label_batch = tf.train.shuffle_batch(
[single_image, single_label],
batch_size=32,
num_threads=4,
capacity=50000,
min_after_dequeue=10000)
#Batching函数相关例子,以函数tf.train.shuffle\_batch为例
#为training, evaluation等操作将样本batching,以下代码使用随机顺序打包样本
def read\_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)
return processed_example, label
def input\_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\_dequeue defines how big a buffer we will randomly sample
# from -- bigger means better shuffling but slower start up and more
# memory used.
# capacity must be larger than min\_after\_dequeue and the amount larger
# determines the maximum we will prefetch. Recommendation:
# min\_after\_dequeue + (num\_threads + a small safety margin) \* 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)
return example_batch, label_batch
#如果需要跟多的并行或文件之间的样本乱序操作,可以使用函数tf.train.shuffle\_batch\_join多实例化reader
def read\_my\_file\_format(filename\_queue):
# 与上例子相同
def input\_pipeline(filenames, batch\_size, read\_threads, num\_epochs=None):
filename_queue = tf.train.string_input_producer(
filenames, num_epochs=num_epochs, shuffle=True)
example_list = [read_my_file_format(filename_queue)
for _ in range(read_threads)]
min_after_dequeue = 10000
capacity = min_after_dequeue + 3 * batch_size
example_batch, label_batch = tf.train.shuffle_batch_join(
example_list, batch_size=batch_size, capacity=capacity,
min_after_dequeue=min_after_dequeue)
return example_batch, label_batch
第三部分
摘要:本系列主要对tf的一些常用概念与方法进行描述。本文主要针对tensorflow的数据IO、图的运行等相关函数进行讲解。为‘Tensorflow一些常用基本概念与函数’系列之三。
1、序言
本文所讲的内容主要为以下相关函数:
操作组 | 操作 |
---|---|
Data IO (Python functions) | TFRecordWrite,rtf_record_iterator |
Running Graphs | Session management,Error classes |
2、tf函数
2.1 数据IO {Data IO (Python functions)}
一个TFRecords 文件为一个字符串序列。这种格式并非随机获取,它比较适合大规模的数据流,而不太适合需要快速分区或其他非序列获取方式。
数据IO {Data IO (Python functions)}
操作 | 描述 |
---|---|
class tf.python_io.TFRecordWriter | 一个用于将记录(records)写入TFRecords文件的类 |
tf.python_io.TFRecordWriter.__init__(path, options=None) | 打开文件路径,并创建一个TFRecordWriter以供写入 |
tf.python_io.TFRecordWriter.write(record) | 将一个字符串records写入文件中 |
tf.python_io.TFRecordWriter.close() | 关闭文件 |
tf.python_io.tf_record_iterator(path, options=None) | 从TFRecords文件中读取记录的迭代器 |
2.2 运行图(Running Graphs)
会话管理 (Session management)
操作 | 描述 |
---|---|
class tf.Session | 运行TF操作的类,一个Session对象将操作节点op封装在一定的环境内运行,同时tensor对象将被计算求值 |
tf.Session.__init__(target=”, graph=None, config=None) | 创建一个新的会话 |
tf.Session.run(fetches, feed_dict=None, options=None, run_metadata=None) | 运行fetches中的操作节点并求其值 |
tf.Session.close() | 关闭会话 |
tf.Session.graph | 返回加载值该会话的图(graph) |
tf.Session.as_default() | 设置该对象为默认会话,并返回一个上下文管理器 |
tf.Session.reset(target, containers=None, config=None) | 重设target的资源容器,并关闭所有连接的会话在0.10版本该功能仅应用在分布会话中target:为执行引擎所连接的目标,其包含有资源容器,该资源容器分布在同一个集群的所有works上 |
class tf.InteractiveSession | 使用在交互式上下文环境的tf会话,比如shell,ipython |
tf.InteractiveSession.close() | 关闭一个InteractiveSession |
tf.get_default_session() | 返回当前线程的默认会话 |
tf.Session
#一个简单的tf.Session例子
# 建立一个graph.
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
# 将graph载入到一个会话session中
sess = tf.Session()
# 计算tensor `c`.
print(sess.run(c))
#一个会话可能会占用一些资源,比如变量、队列和读取器(reader)。释放这些不再使用的资源非常重要。
#使用close()方法关闭会话,或者使用上下文管理器,释放资源。
# 使用`close()`方法.
sess = tf.Session()
sess.run(...)
sess.close()
# 使用上下文管理器
with tf.Session() as sess:
sess.run(...)
tf.Session()的变量设置, ConfigProto protocol buffer为会话提供了不同的配置选项。比如,创建一个会话,对设备布局使用软约束条件,以及对分布
# Launch the graph in a session that allows soft device placement and
# logs the placement decisions.
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True,
log_device_placement=True))
tf.Session.run
a = tf.constant([10, 20])
b = tf.constant([1.0, 2.0])
# 'fetches' 可以为单个数
v = session.run(a)
# v is the numpy array [10, 20]
# 'fetches' 可以为一个list.
v = session.run([a, b])
# v a Python list with 2 numpy arrays: the numpy array [10, 20] and the
# 1-D array [1.0, 2.0]
# 'fetches' 可以是 lists, tuples, namedtuple, dicts中的任意:
MyData = collections.namedtuple('MyData', ['a', 'b'])
v = session.run({'k1': MyData(a, b), 'k2': [b, a]})
# v 为一个dict,并有
# v['k1'] is a MyData namedtuple with 'a' the numpy array [10, 20] and
# 'b' the numpy array [1.0, 2.0]
# v['k2'] is a list with the numpy array [1.0, 2.0] and the numpy array
# [10, 20].
tf.Session.as_default()
使用关键字with指定会话, 可以在会话中执行Operation.run()或Tensor.eval(),以得到运行的tensor结果
c = tf.constant(..)
sess = tf.Session()
with sess.as_default():
assert tf.get_default_session() is sess
print(c.eval())
使用函数tf.get_default_session()来得到当前默认的会话
需要注意的是,退出该as_default上下文管理器时,并没有关闭该会话(session ),必须明确的关闭会话
c = tf.constant(...)
sess = tf.Session()
with sess.as_default():
print(c.eval())
# ...
with sess.as_default():
print(c.eval())
#关闭会话
sess.close()
#使用 with tf.Session()方式可以创建并自动关闭会话
tf.InteractiveSession
sess = tf.InteractiveSession()
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
# 我们直接使用'c.eval()' 而没有通过'sess'
print(c.eval())
sess.close()
以上的例子,在非交互会话的版本中为,
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
with tf.Session():
# We can also use 'c.eval()' here.
print(c.eval())
ABC
错误类 (Error classes)
操作 | 描述 |
---|---|
class tf.OpError | 一个基本的错误类型,在当TF执行失败时候报错 |
tf.OpError.op | 返回执行失败的操作节点,有的操作如Send或Recv可能不会返回,那就要用用到node_def方法 |
tf.OpError.node_def | 以NodeDef proto形式表示失败的op |
tf.OpError.error_code | 描述该错误的整数错误代码 |
tf.OpError.message | 返回错误信息 |
class tf.errors.CancelledError | 当操作或者阶段呗取消时候报错 |
class tf.errors.UnknownError | 未知错误类型 |
class tf.errors.InvalidArgumentError | 在接收到非法参数时候报错 |
class tf.errors.NotFoundError | 当发现不存在所请求的一个实体时候,比如文件或目录 |
class tf.errors.AlreadyExistsError | 当创建的实体已经存在的时候报错 |
class tf.errors.PermissionDeniedError | 没有执行权限做某操作的时候报错 |
class tf.errors.ResourceExhaustedError | 资源耗尽时报错 |
class tf.errors.FailedPreconditionError | 系统没有条件执行某个行为时候报错 |
class tf.errors.AbortedError | 操作中止时报错,常常发生在并发情形 |
class tf.errors.OutOfRangeError | 超出范围报错 |
class tf.errors.UnimplementedError | 某个操作没有执行时报错 |
class tf.errors.InternalError | 当系统经历了一个内部错误时报出 |
class tf.errors.DataLossError | 当出现不可恢复的错误例如在运行 tf.WholeFileReader.read()读取整个文件的同时文件被删减 |
tf.errors.XXXXX.__init__(node_def, op, message) | 使用该形式方法创建以上各种错误类 |
摘要:本系列主要对tf的一些常用概念与方法进行描述。本文主要针对tensorflow的模型训练Training与测试Testing等相关函数进行讲解。为‘Tensorflow一些常用基本概念与函数’系列之四。
1、序言
本文所讲的内容主要为以下列表中相关函数。函数training()通过梯度下降法为最小化损失函数增加了相关的优化操作,在训练过程中,先实例化一个优化函数,比如 tf.train.GradientDescentOptimizer,并基于一定的学习率进行梯度优化训练:
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
然后,可以设置 一个用于记录全局训练步骤的单值。以及使用minimize()操作,该操作不仅可以优化更新训练的模型参数,也可以为全局步骤(global step)计数。与其他tensorflow操作类似,这些训练操作都需要在tf.session会话中进行
global_step = tf.Variable(0, name='global_step', trainable=False)
train_op = optimizer.minimize(loss, global_step=global_step)
操作组 | 操作 |
---|---|
Training | Optimizers,Gradient Computation,Gradient Clipping,Distributed execution |
Testing | Unit tests,Utilities,Gradient checking |
2、Tensorflow函数
2.1 训练 (Training)
一个TFRecords 文件为一个字符串序列。这种格式并非随机获取,它比较适合大规模的数据流,而不太适合需要快速分区或其他非序列获取方式。
█ 优化 (Optimizers)
tf中各种优化类提供了为损失函数计算梯度的方法,其中包含比较经典的优化算法,比如GradientDescent 和Adagrad。
▶▶class tf.train.Optimizer
操作 | 描述 |
---|---|
class tf.train.Optimizer | 基本的优化类,该类不常常被直接调用,而较多使用其子类,比如GradientDescentOptimizer, AdagradOptimizer或者MomentumOptimizer |
tf.train.Optimizer.__init__(use_locking, name) | 创建一个新的优化器,该优化器必须被其子类(subclasses)的构造函数调用 |
tf.train.Optimizer.minimize(loss, global_step=None, var_list=None, gate_gradients=1, aggregation_method=None, colocate_gradients_with_ops=False, name=None, grad_loss=None) | 添加操作节点,用于最小化loss,并更新var_list该函数是简单的合并了compute_gradients()与apply_gradients()函数返回为一个优化更新后的var_list,如果global_step非None,该操作还会为global_step做自增操作 |
tf.train.Optimizer.compute_gradients(loss,var_list=None, gate_gradients=1,aggregation_method=None, colocate_gradients_with_ops=False, grad_loss=None) | 对var_list中的变量计算loss的梯度该函数为函数minimize()的第一部分,返回一个以元组(gradient, variable)组成的列表 |
tf.train.Optimizer.apply_gradients(grads_and_vars, global_step=None, name=None) | 将计算出的梯度应用到变量上,是函数minimize()的第二部分,返回一个应用指定的梯度的操作Operation,对global_step做自增操作 |
tf.train.Optimizer.get_name() | 获取名称 |
▷ class tf.train.Optimizer
用法
# Create an optimizer with the desired parameters.
opt = GradientDescentOptimizer(learning_rate=0.1)
# Add Ops to the graph to minimize a cost by updating a list of variables.
# "cost" is a Tensor, and the list of variables contains tf.Variable objects.
opt_op = opt.minimize(cost, var_list=<list of variables>)
# Execute opt\_op to do one step of training:
opt_op.run()
▶▶在使用它们之前处理梯度
使用minimize()操作,该操作不仅可以计算出梯度,而且还可以将梯度作用在变量上。如果想在使用它们之前处理梯度,可以按照以下三步骤使用optimizer :
1、使用函数compute_gradients()计算梯度
2、按照自己的愿望处理梯度
3、使用函数apply_gradients()应用处理过后的梯度
例如:
# 创建一个optimizer.
opt = GradientDescentOptimizer(learning_rate=0.1)
# 计算<list of variables>相关的梯度
grads_and_vars = opt.compute_gradients(loss, <list of variables>)
# grads\_and\_vars为tuples (gradient, variable)组成的列表。
#对梯度进行想要的处理,比如cap处理
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]
# 令optimizer运用capped的梯度(gradients)
opt.apply_gradients(capped_grads_and_vars)
▶▶选通梯度(Gating Gradients)
函数minimize() 与compute_gradients()都含有一个参数gate_gradient,用于控制在应用这些梯度时并行化的程度。
其值可以取:GATE_NONE, GATE_OP 或 GATE_GRAPH
GATE_NONE : 并行地计算和应用梯度。提供最大化的并行执行,但是会导致有的数据结果没有再现性。比如两个matmul操作的梯度依赖输入值,使用GATE_NONE可能会出现有一个梯度在其他梯度之前便应用到某个输入中,导致出现不可再现的(non-reproducible)结果
GATE_OP: 对于每个操作Op,确保每一个梯度在使用之前都已经计算完成。这种做法防止了那些具有多个输入,并且梯度计算依赖输入情形中,多输入Ops之间的竞争情况出现。
GATE_GRAPH: 确保所有的变量对应的所有梯度在他们任何一个被使用前计算完成。该方式具有最低级别的并行化程度,但是对于想要在应用它们任何一个之前处理完所有的梯度计算时很有帮助的。
█ Slots
一些optimizer的之类,比如 MomentumOptimizer 和 AdagradOptimizer 分配和管理着额外的用于训练的变量。这些变量称之为’Slots’,Slots有相应的名称,可以向optimizer访问的slots名称。有助于在log debug一个训练算法以及报告slots状态
操作 | 描述 |
---|---|
tf.train.Optimizer.get_slot_names() | 返回一个由Optimizer所创建的slots的名称列表 |
tf.train.Optimizer.get_slot(var, name) | 返回一个name所对应的slot,name是由Optimizer为var所创建var为用于传入 minimize() 或 apply_gradients()的变量 |
class tf.train.GradientDescentOptimizer | 使用梯度下降算法的Optimizer |
tf.train.GradientDescentOptimizer.__init__(learning_rate, use_locking=False, name=’GradientDescent’) | 构建一个新的梯度下降优化器(Optimizer) |
class tf.train.AdadeltaOptimizer | 使用Adadelta算法的Optimizer |
tf.train.AdadeltaOptimizer.__init__(learning_rate=0.001, rho=0.95, epsilon=1e-08, use_locking=False, name=’Adadelta’) | 创建Adadelta优化器 |
class tf.train.AdagradOptimizer | 使用Adagrad算法的Optimizer |
tf.train.AdagradOptimizer.__init__(learning_rate, initial_accumulator_value=0.1, use_locking=False, name=’Adagrad’) | 创建Adagrad优化器 |
class tf.train.MomentumOptimizer | 使用Momentum算法的Optimizer |
tf.train.MomentumOptimizer.__init__(learning_rate, momentum, use_locking=False, name=’Momentum’, use_nesterov=False) | 创建momentum优化器momentum:动量,一个tensor或者浮点值 |
class tf.train.AdamOptimizer | 使用Adam 算法的Optimizer |
tf.train.AdamOptimizer.__init__(learning_rate=0.001,beta1=0.9, beta2=0.999, epsilon=1e-08,use_locking=False, name=’Adam’) | 创建Adam优化器 |
class tf.train.FtrlOptimizer | 使用FTRL 算法的Optimizer |
tf.train.FtrlOptimizer.__init__(learning_rate, learning_rate_power=-0.5, initial_accumulator_value=0.1, l1_regularization_strength=0.0, l2_regularization_strength=0.0,use_locking=False, name=’Ftrl’) | 创建FTRL算法优化器 |
class tf.train.RMSPropOptimizer | 使用RMSProp算法的Optimizer |
tf.train.RMSPropOptimizer.__init__(learning_rate, decay=0.9, momentum=0.0, epsilon=1e-10, use_locking=False, name=’RMSProp’) | 创建RMSProp算法优化器 |
▷ tf.train.AdamOptimizer
Adam 的基本运行方式,首先初始化:
m_0 <- 0 (Initialize initial 1st moment vector)
v_0 <- 0 (Initialize initial 2nd moment vector)
t <- 0 (Initialize timestep)
在论文中的 section2 的末尾所描述了更新规则,该规则使用梯度g来更新变量:
t <- t + 1
lr_t <- learning_rate * sqrt(1 - beta2^t) / (1 - beta1^t)
m_t <- beta1 * m_{t-1} + (1 - beta1) * g
v_t <- beta2 * v_{t-1} + (1 - beta2) * g * g
variable <- variable - lr_t * m_t / (sqrt(v_t) + epsilon)
其中epsilon 的默认值1e-8可能对于大多数情况都不是一个合适的值。例如,当在ImageNet上训练一个 Inception network时比较好的选择为1.0或者0.1。
需要注意的是,在稠密数据中即便g为0时, m_t, v_t 以及variable都将会更新。而在稀疏数据中,m_t, v_t 以及variable不被更新且值为零。
█ 梯度计算与截断(Gradient Computation and Clipping)
TensorFlow 提供了计算给定tf计算图的求导函数,并在图的基础上增加节点。优化器(optimizer )类可以自动的计算网络图的导数,但是优化器中的创建器(creators )或者专业的人员可以通过本节所述的函数调用更底层的方法。
操作 | 描述 |
---|---|
tf.gradients(ys, xs, grad_ys=None, name=’gradients’, colocate_gradients_with_ops=False, gate_gradients=False, aggregation_method=None) | 构建一个符号函数,计算ys关于xs中x的偏导的和,返回xs中每个x对应的sum(dy/dx) |
tf.stop_gradient(input, name=None) | 停止计算梯度,在EM算法、Boltzmann机等可能会使用到 |
tf.clip_by_value(t, clip_value_min, clip_value_max, name=None) | 基于定义的min与max对tesor数据进行截断操作,目的是为了应对梯度爆发或者梯度消失的情况 |
tf.clip_by_norm(t, clip_norm, axes=None, name=None) | 使用L2范式标准化tensor最大值为clip_norm返回 t * clip_norm / l2norm(t) |
tf.clip_by_average_norm(t, clip_norm, name=None) | 使用平均L2范式规范tensor数据t,并以clip_norm为最大值返回 t * clip_norm / l2norm_avg(t) |
tf.clip_by_global_norm(t_list, clip_norm, use_norm=None, name=None) | 返回t_list[i] * clip_norm / max(global_norm, clip_norm)其中global_norm = sqrt(sum([l2norm(t)**2 for t in t_list])) |
tf.global_norm(t_list, name=None) | 返回global_norm = sqrt(sum([l2norm(t)**2 for t in t_list])) |
█ 退化学习率(Decaying the learning rate)
操作 | 描述 |
---|---|
tf.train.exponential_decay(learning_rate, global_step, decay_steps, decay_rate, staircase=False, name=None) | 对学习率进行指数衰退 |
▷ tf.train.exponential_decay
#该函数返回以下结果
decayed_learning_rate = learning_rate *
decay_rate ^ (global_step / decay_steps)
##例: 以0.96为基数,每100000 步进行一次学习率的衰退
global_step = tf.Variable(0, trainable=False)
starter_learning_rate = 0.1
learning_rate = tf.train.exponential_decay(starter_learning_rate, global_step,
100000, 0.96, staircase=True)
# Passing global\_step to minimize() will increment it at each step.
learning_step = (
tf.train.GradientDescentOptimizer(learning_rate)
.minimize(...my loss..., global_step=global_step)
)
█ 移动平均(Moving Averages)
一些训练优化算法,比如GradientDescent 和Momentum 在优化过程中便可以使用到移动平均方法。使用移动平均常常可以较明显地改善结果。
操作 | 描述 |
---|---|
class tf.train.ExponentialMovingAverage | 将指数衰退加入到移动平均中 |
tf.train.ExponentialMovingAverage.apply(var_list=None) | 对var_list变量保持移动平均 |
tf.train.ExponentialMovingAverage.average_name(var) | 返回var均值的变量名称 |
tf.train.ExponentialMovingAverage.average(var) | 返回var均值变量 |
tf.train.ExponentialMovingAverage.variables_to_restore(moving_avg_variables=None) | 返回用于保存的变量名称的映射 |
▷ tf.train.ExponentialMovingAverage
# Example usage when creating a training model:
# Create variables.
var0 = tf.Variable(...)
var1 = tf.Variable(...)
# ... use the variables to build a training model...
...
# Create an op that applies the optimizer. This is what we usually
# would use as a training op.
opt_op = opt.minimize(my_loss, [var0, var1])
# Create an ExponentialMovingAverage object
ema = tf.train.ExponentialMovingAverage(decay=0.9999)
# Create the shadow variables, and add ops to maintain moving averages
# of var0 and var1.
maintain_averages_op = ema.apply([var0, var1])
# Create an op that will update the moving averages after each training
# step. This is what we will use in place of the usual training op.
with tf.control_dependencies([opt_op]):
training_op = tf.group(maintain_averages_op)
...train the model by running training_op...
#Example of restoring the shadow variable values:
# Create a Saver that loads variables from their saved shadow values.
shadow_var0_name = ema.average_name(var0)
shadow_var1_name = ema.average_name(var1)
saver = tf.train.Saver({shadow_var0_name: var0, shadow_var1_name: var1})
saver.restore(...checkpoint filename...)
# var0 and var1 now hold the moving average values
▷ tf.train.ExponentialMovingAverage.variables_to_restore
variables_to_restore = ema.variables_to_restore()
saver = tf.train.Saver(variables_to_restore)
█ 协调器和队列运行器(Coordinator and QueueRunner)
查看queue中,queue相关的内容,了解tensorflow中队列的运行方式。
操作 | 描述 |
---|---|
class tf.train.Coordinator | 线程的协调器 |
tf.train.Coordinator.clear_stop() | 清除停止标记 |
tf.train.Coordinator.join(threads=None, stop_grace_period_secs=120) | 等待线程终止threads:一个threading.Threads的列表,启动的线程,将额外加入到registered的线程中 |
tf.train.Coordinator.register_thread(thread) | Register一个用于join的线程 |
tf.train.Coordinator.request_stop(ex=None) | 请求线程结束 |
tf.train.Coordinator.should_stop() | 检查是否被请求停止 |
tf.train.Coordinator.stop_on_exception() | 上下文管理器,当一个例外出现时请求停止 |
tf.train.Coordinator.wait_for_stop(timeout=None) | 等待Coordinator提示停止进程 |
class tf.train.QueueRunner | 持有一个队列的入列操作列表,用于线程中运行queue:一个队列enqueue_ops: 用于线程中运行的入列操作列表 |
tf.train.QueueRunner.create_threads(sess, coord=None, daemon=False, start=False) | 创建运行入列操作的线程,返回一个线程列表 |
tf.train.QueueRunner.from_proto(queue_runner_def) | 返回由queue_runner_def创建的QueueRunner对象 |
tf.train.add_queue_runner(qr, collection=’queue_runners’) | 增加一个QueueRunner到graph的收集器(collection )中 |
tf.train.start_queue_runners(sess=None, coord=None, daemon=True, start=True, collection=’queue_runners’) | 启动所有graph收集到的队列运行器(queue runners) |
▷ class tf.train.Coordinator
#Coordinator的使用,用于多线程的协调
try:
...
coord = Coordinator()
# Start a number of threads, passing the coordinator to each of them.
...start thread 1...(coord, ...)
...start thread N...(coord, ...)
# Wait for all the threads to terminate, give them 10s grace period
coord.join(threads, stop_grace_period_secs=10)
except RuntimeException:
...one of the threads took more than 10s to stop after request_stop()
...was called.
except Exception:
...exception that was passed to coord.request_stop()
▷ tf.train.Coordinator.stop_on_exception()
with coord.stop_on_exception():
# Any exception raised in the body of the with
# clause is reported to the coordinator before terminating
# the execution of the body.
...body...
#等价于
try:
...body...
exception Exception as ex:
coord.request_stop(ex)
█ 布执行(Distributed execution)
可以阅读TensorFlow的分布式学习框架简介查看更多tensorflow分布式细节。
操作 | 描述 |
---|---|
class tf.train.Server | 一个进程内的tensorflow服务,用于分布式训练 |
tf.train.Server.init(server_or_cluster_def, job_name=None, task_index=None, protocol=None,config=None, start=True) | 创建一个新的服务,其中job_name, task_index, 和protocol为可选参数,优先级高于server_or_cluster_def中相关信息server_or_cluster_def : 为一个tf.train.ServerDef 或 tf.train.ClusterDef 协议(protocol)的buffer,或者一个tf.train.ClusterSpec对象 |
tf.train.Server.create_local_server(config=None, start=True) | 创建一个新的运行在本地主机的单进程集群 |
tf.train.Server.target | 返回tf.Session所连接的目标服务器 |
tf.train.Server.server_def | 返回该服务的tf.train.ServerDef |
tf.train.Server.start() | 开启服务 |
tf.train.Server.join() | 阻塞直到服务已经关闭 |
# | |
---|---|
class tf.train.Supervisor | 一个训练辅助器,用于checkpoints模型以及计算的summaries。该监视器只是一个小的外壳(wrapper),用于Coordinator, a Saver, 和a SessionManager周围 |
tf.train.Supervisor.__init__(graph=None, ready_op=0, is_chief=True, init_op=0, init_feed_dict=None, local_init_op=0, logdir=None, summary_op=0, saver=0, global_step=0, save_summaries_secs=120, save_model_secs=600, recovery_wait_secs=30, stop_grace_secs=120,checkpoint_basename=’model.ckpt’, session_manager=None, summary_writer=0, init_fn=None) | 创建一个监视器Supervisor |
tf.train.Supervisor.managed_session(master=”, config=None, start_standard_services=True, close_summary_writer=True) | 返回一个管路session的上下文管理器 |
tf.train.Supervisor.prepare_or_wait_for_session(master=”, config=None, wait_for_checkpoint=False, max_wait_secs=7200, start_standard_services=True) | 确保model已经准备好 |
tf.train.Supervisor.start_standard_services(sess) | 为sess启动一个标准的服务 |
tf.train.Supervisor.start_queue_runners(sess, queue_runners=None) | 为QueueRunners启动一个线程,queue_runners为一个QueueRunners列表 |
tf.train.Supervisor.summary_computed(sess, summary, global_step=None) | 指示计算的summary |
tf.train.Supervisor.stop(threads=None, close_summary_writer=True) | 停止服务以及协调器(coordinator),并没有关闭session |
tf.train.Supervisor.request_stop(ex=None) | 参考Coordinator.request_stop() |
tf.train.Supervisor.should_stop() | 参考Coordinator.should_stop() |
tf.train.Supervisor.stop_on_exception() | 参考 Coordinator.stop_on_exception() |
tf.train.Supervisor.Loop(timer_interval_secs, target, args=None, kwargs=None) | 开启一个循环器线程用于调用一个函数每经过timer_interval_secs秒执行,target(*args, **kwargs) |
tf.train.Supervisor.coord | 返回监督器(Supervisor)使用的协调器(Coordinator ) |
# | |
---|---|
class tf.train.SessionManager | 训练的辅助器,用于从checkpoint恢复数据以及创建一个session |
tf.train.SessionManager.__init__(local_init_op=None, ready_op=None, graph=None, recovery_wait_secs=30) | 创建一个SessionManager |
tf.train.SessionManager.prepare_session(master, init_op=None, saver=None, checkpoint_dir=None, wait_for_checkpoint=False, max_wait_secs=7200, config=None, init_feed_dict=None, init_fn=None) | 创建一个session,并确保model可以被使用 |
tf.train.SessionManager.recover_session(master, saver=None, checkpoint_dir=None, wait_for_checkpoint=False, max_wait_secs=7200, config=None) | 创建一个session,如果可以的话,使用恢复方法创建 |
tf.train.SessionManager.wait_for_session(master, config=None, max_wait_secs=inf) | 创建一个session,并等待model准备完成 |
# | |
---|---|
class tf.train.ClusterSpec | 将一个集群表示为一系列“tasks”,并整合至“jobs”中 |
tf.train.ClusterSpec.as_cluster_def() | 返回该cluster中一个tf.train.ClusterDef协议的buffer |
tf.train.ClusterSpec.as_dict() | 返回一个字典,由job名称对应于网络地址 |
tf.train.ClusterSpec.job_tasks(job_name) | 返回一个给定的job对应的task列表 |
tf.train.ClusterSpec.jobs | 返回该cluster的job名称列表 |
tf.train.replica_device_setter(ps_tasks=0, ps_device=’/job:ps’, worker_device=’/job:worker’, merge_devices=True, cluster=None, ps_ops=None) | 返回一个设备函数(device function),以在建立一个副本graph的时候使用,设备函数(device function)用在with tf.device(device_function)中 |
▷ tf.train.Server
server = tf.train.Server(...)
with tf.Session(server.target):
# ...
▷ tf.train.Supervisor
相关参数:
ready_op : 一维 字符串 tensor。该tensor是用过监视器在prepare_or_wait_for_session()计算,检查model是否准备好可以使用。如果准备好,将返回一个空阵列,如果为None,该model没有被检查。
is_chief : 如果为True,创建一个主监视器用于负责初始化与模型的恢复,若为False,则依赖主监视器。
init_op : 一个操作,用于模型不能恢复时的初始化操作。默认初始化所有操作
local_init_op : 可被所有监视器运行的初始化操作。
logdir : 设置log目录
summary_op : 一个操作(Operation ),返回Summary 和事件logs,需要设置 logdir
saver : 一个Saver对象
save_summaries_secs : 保存summaries的间隔秒数
save_model_secs : 保存model的间隔秒数
checkpoint_basename : checkpoint保存的基本名称
- 使用在单进程中
with tf.Graph().as_default():
...add operations to the graph...
# Create a Supervisor that will checkpoint the model in '/tmp/mydir'.
sv = Supervisor(logdir='/tmp/mydir')
# Get a TensorFlow session managed by the supervisor.
with sv.managed_session(FLAGS.master) as sess:
# Use the session to train the graph.
while not sv.should_stop():
sess.run(<my_train_op>)
# 在上下文管理器with sv.managed\_session()内,所有在graph的变量都被初始化。
# 或者说,一些服务器checkpoint相应模型并增加summaries至事件log中。
# 如果有例外发生,should\_stop()将返回True
- 使用在多副本运行情况中
要使用副本训练已经部署在集群上的相同程序,必须指定其中一个task为主要,该task处理 initialization, checkpoints, summaries, 和recovery相关事物。其他task依赖该task。
# Choose a task as the chief. This could be based on server\_def.task\_index,
# or job\_def.name, or job\_def.tasks. It's entirely up to the end user.
# But there can be only one \*chief\*.
is_chief = (server_def.task_index == 0)