tensorflow 函数解析
1.optimizer.minimize(loss, var_list)
TensorFlow为我们提供了丰富的优化函数,例如GradientDescentOptimizer。这个方法会自动根据loss计算对应variable的导数。示例如下:
loss = ...
opt = tf.tf.train.GradientDescentOptimizer(learning_rate=0.1)
train_op = opt.minimize(loss)
init = tf.initialize_all_variables()
with tf.Seesion() as sess:
sess.run(init)
for step in range(10):
session.run(train_op)
看一下minimize()
的源代码(为方便说明,部分参数已删除):
1 def minimize(self, loss, global_step=None, var_list=None, name=None): 2 3 grads_and_vars = self.compute_gradients(loss, var_list=var_list) 4 5 vars_with_grad = [v for g, v in grads_and_vars if g is not None] 6 if not vars_with_grad: 7 raise ValueError( 8 "No gradients provided for any variable, check your graph for ops" 9 " that do not support gradients, between variables %s and loss %s." % 10 ([str(v) for _, v in grads_and_vars], loss)) 11 12 return self.apply_gradients(grads_and_vars, global_step=global_step, 13 name=name)
源代码可以知道minimize()
实际上包含了两个步骤,即compute_gradients
和apply_gradients
,前者用于计算梯度,后者用于使用计算得到的梯度来更新对应的variable,梯度修剪主要避免训练梯度爆炸和消失问题。下面对这两个函数做具体介绍。
1.1 computer_gradients(loss, val_list)
参数含义:
- loss: 需要被优化的Tensor
- val_list: Optional list or tuple of
tf.Variable
to update to minimizeloss
. Defaults to the list of variables collected in the graph under the keyGraphKeys.TRAINABLE_VARIABLES
.
简单说该函数就是用于计算loss对于指定val_list的导数的,最终返回的是元组列表,即[(gradient, variable),...]。
1 x = tf.Variable(initial_value=50., dtype='float32') 2 w = tf.Variable(initial_value=10., dtype='float32') 3 y = w*x 4 5 opt = tf.train.GradientDescentOptimizer(0.1) 6 grad = opt.compute_gradients(y, [w,x]) 7 with tf.Session() as sess: 8 sess.run(tf.global_variables_initializer()) 9 print(sess.run(grad))
>>> [(50.0, 10.0), (10.0, 50.0)]
可以看到返回了一个list,list中的元素是元组。第一个元组第一个元素是50,表示∂y∂w∂y∂w的计算结果,第二个元素表示ww。第二个元组同理不做赘述。
其中tf.gradients(loss, tf.variables)
的作用和这个函数类似,但是它只会返回计算得到的梯度,而不会返回对应的variable。
tf.gradients( ys, xs, grad_ys=None, name='gradients', colocate_gradients_with_ops=False, gate_gradients=False, aggregation_method=None, stop_gradients=None, unconnected_gradients=tf.UnconnectedGradients.NONE )
返回值:A list of sum(dy/dx) for each x in xs.
a = tf.constant(0.) b = 2 * a g = tf.gradients(a + b, [a, b], stop_gradients=[a, b]) 结果:[1.0, 1.0] #stop_gradients使得指定变量不被求导,即视为常量
结果对比:
with tf.Graph().as_default(): x = tf.Variable(initial_value=3., dtype='float32') w = tf.Variable(initial_value=4., dtype='float32') y = w*x grads = tf.gradients(y, [w]) print(grads) opt = tf.train.GradientDescentOptimizer(0.1) grads_vals = opt.compute_gradients(y, [w]) print(grad_vals) >>> [<tf.Tensor 'gradients/mul_grad/Mul:0' shape=() dtype=float32>] [(<tf.Tensor 'gradients_1/mul_grad/tuple/control_dependency:0' shape=() dtype=float32>, <tf.Variable 'Variable_1:0' shape=() dtype=float32_ref>)]
1.2 apply_gradients(grads_and_vars, global_step=None, name=None)
apply_gradients( grads_and_vars, global_step=None, name=None )
grads_and_vars: List of (gradient, variable) pairs as returned by compute_gradients().
global_step: Optional Variable to increment by one after the variables have been updated.
name: Optional name for the returned operation. Default to the name passed to the Optimizer constructor.
该函数的作用是将compute_gradients()
返回的值作为输入参数对variable进行更新。
那为什么minimize()
会分开两个步骤呢?原因是因为在某些情况下我们需要对梯度做一定的修正,例如为了防止梯度消失(gradient vanishing)或者梯度爆炸(gradient explosion),我们需要事先干预一下以免程序出现Nan的尴尬情况;有的时候也许我们需要给计算得到的梯度乘以一个权重或者其他乱七八糟的原因,所以才分开了两个步骤。
with tf.Graph().as_default(): x = tf.Variable(initial_value=3., dtype='float32') w = tf.Variable(initial_value=4., dtype='float32') y = w*x opt = tf.train.GradientDescentOptimizer(0.1) grads_vals = opt.compute_gradients(y, [w]) for i, (g, v) in enumerate(grads_vals): if g is not None: grads_vals[i] = (tf.clip_by_norm(g, 5), v) # clip gradients train_op = opt.apply_gradients(grads_vals) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run(grads_vals)) print(sess.run([x,w,y])) >>> [(3.0, 4.0)] [3.0, 4.0, 12.0]
2.tf.clip_by_global_norm
Args:
t_list
: A tuple or list of mixed , , or None.Tensors
IndexedSlices
clip_norm
: A 0-D (scalar) > 0. The clipping ratio.Tensor
use_norm
: A 0-D (scalar) of type (optional). The global norm to use. If not provided, is used to compute the norm.Tensor
float
global_norm()
name
: A name for the operation (optional).
Returns:
list_clipped
: A list of of the same type as .Tensors
list_t
global_norm
: A 0-D (scalar) representing the global norm.Tensor
tf.clip_by_global_norm( t_list, clip_norm, use_norm=None, name=None )
3.tf.trainable_variables(), tf.all_variables(), tf.global_variables()的使用
3.1 tf.trainable_variables()
tf.trainable_variables(scope=None)
这个函数可以也仅可以查看可训练的变量,在我们生成变量时,无论是使用tf.Variable()还是tf.get_variable()生成变量,都会涉及一个参数trainable,其默认为True。以tf.Variable()为例:
__init__( initial_value=None, trainable=True, collections=None, validate_shape=True, ... )
对于一些我们不需要训练的变量,比较典型的例如学习率或者计步器这些变量,我们都需要将trainable设置为False,这时tf.trainable_variables() 就不会打印这些变量。举个简单的例子,在下图中共定义了4个变量,分别是一个权重矩阵,一个偏置向量,一个学习率和计步器,其中前两项是需要训练的而后两项则不需要。
w1=tf.Variable(tf.random_normal([255,2000]),'w1') b1=tf.get_variable('b1',[2000]) learning_rate=tf.Variable(0.5,trainable=False) global_step=tf.Variable(0,trainable=False)
tf.trainable_variables() Out[3]: [<tf.Variable 'Variable:0' shape=(255, 2000) dtype=float32_ref>, <tf.Variable 'b1:0' shape=(2000,) dtype=float32_ref>] compare: tf.global_variables() [<tf.Variable 'Variable:0' shape=(255, 2000) dtype=float32_ref>, <tf.Variable 'b1:0' shape=(2000,) dtype=float32_ref>, <tf.Variable 'Variable_1:0' shape=() dtype=float32_ref>, <tf.Variable 'Variable_2:0' shape=() dtype=int32_ref>]
4.tf.nn.rnn_cell.BasicRNNCell()
为什么使用tanh?
为了克服梯度消失问题,我们需要一个二阶导数在趋近零点之前能维持很长距离的函数。tanh是具有这种属性的合适的函数。
为什么要使用Sigmoid?
由于Sigmoid函数可以输出0或1,它可以用来决定忘记或记住信息。
信息通过很多这样的LSTM单元。图中标记的LSTM单元有三个主要部分:
- LSTM有一个特殊的架构,它可以让它忘记不必要的信息。Sigmoid层取得输入X(t)和h(t-1),并决定从旧输出中删除哪些部分(通过输出0实现)。在我们的例子中,当输入是“他有一个女性朋友玛丽亚”时,“大卫”的性别可以被遗忘,因为主题已经变成了玛丽亚。这个门被称为遗忘门f(t)。这个门的输出是f(t)* c(t-1)。
- 下一步是决定并存储记忆单元新输入X(t)的信息。Sigmoid层决定应该更新或忽略哪些新信息。tanh层根据新的输入创建所有可能的值的向量。将它们相乘以更新这个新的记忆单元。然后将这个新的记忆添加到旧记忆c(t-1)中,以给出c(t)。在我们的例子中,对于新的输入,他有一个女性朋友玛丽亚,玛丽亚的性别将被更新。当输入的信息是,“玛丽亚在纽约一家著名的餐馆当厨师,最近他们在学校的校友会上碰面。”时,像“著名”、“校友会”这样的词可以忽略,像“厨师”、“餐厅”和“纽约”这样的词将被更新。
- 最后,我们需要决定我们要输出的内容。Sigmoid层决定我们要输出的记忆单元的哪些部分。然后,我们把记忆单元通过tanh生成所有可能的值乘以Sigmoid门的输出,以便我们只输出我们决定的部分。在我们的例子中,我们想要预测空白的单词,我们的模型知道它是一个与它记忆中的“厨师”相关的名词,它可以很容易的回答为“烹饪”。我们的模型没有从直接依赖中学习这个答案,而是从长期依赖中学习它。
5.LSTM
LSTM,Long Short Term Memory Networks,是 RNN 的一个变种,经试验它可以用来解决更多问题,并取得了非常好的效果。LSTM Cell 的结构如下:
首先它的类是 BasicLSTMCell 类,继承了 RNNCell 类,其初始化方法 init() 实现如下: def __init__(self, num_units, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None): super(BasicLSTMCell, self).__init__(_reuse=reuse) if not state_is_tuple: #isinstance(a,tuple)
logging.warn('%s: Using a concatenated state is slower and will soon be ' 'deprecated. Use state_is_tuple=True.', self) self._num_units = num_units self._forget_bias = forget_bias self._state_is_tuple = state_is_tuple self._activation = activation or math_ops.tanh #tf.nn.relu、tf.sigmoid、tf.tanh self._linear = None
这里必须传入的参数仍然是 num_units,即神经元的个数,然后 forget_bias 是初始化 Forget Gate 的偏置大小,state_is_tuple 指的是输出状态类型是元组类型,activation 代表默认激活函数,reuse 代表是否可以被重复使用。
接下来看下 state_size() 方法和 output_size() 方法,实现如下: @property def state_size(self): return (LSTMStateTuple(self._num_units, self._num_units) #存储LSTM单元的state_size,zero_state和output state的元组。按顺序存储两个元素(c,h),其中c是隐藏状态,h是输出。只有在state_is_tuple=True是才使用 if self._state_is_tuple else 2 * self._num_units) @property def output_size(self): return self._num_units
这里 state_size() 方法变了,因为输出的 state 需要将 Ct 和隐含状态合并,所以它需要包含两部分的内容,如果传入的参数 state_is_tuple 为 True 的话,状态会被表示成一个元组,否则会是 num_units 乘以 2 的数字,默认是元组形式。output_size() 方法则保持不变。
import tensorflow as tf output_dim=128 lstm=tf.nn.rnn_cell.BasicLSTMCell(output_dim) batch_size=10 #批处理大小 timesteps=40 #时间步长 embedding_dim=300 #词向量维度 inputs=tf.Variable(tf.random_normal([batch_size,embedding_dim])) previous_state = (tf.random_normal(shape=(batch_size, output_dim)), tf.random_normal(shape=(batch_size, output_dim))) output,(new_h, new_state)=lstm(inputs,previous_state) print(output.shape) #(10, 128) print(new_h.shape) #(10, 128) print(new_state.shape) #(10, 128)
实例化了一个 _Linear 类,这个类实际上就是做线性变换的类,将二者传递过来,然后直接调用,就实现了 w * [inputs, state] + b 的线性变换,其中 _Linear 类的 __call__() 方法实现如下:
def __call__(self, args): if not self._is_sequence: args = [args] if len(args) == 1: res = math_ops.matmul(args[0], self._weights) else: res = math_ops.matmul(array_ops.concat(args, 1), self._weights) if self._build_bias: res = nn_ops.bias_add(res, self._biases) return res
很明显这里传递了 [inputs, state] 作为 __call__() 方法的 args,会执行 concat() 和 matmul() 方法,然后接着再执行 bias_add() 方法,这样就实现了线性变换。最后回到 BasicRNNCell 的 call() 方法中,在 _linear() 方法外面又包括了一层 _activation() 方法,即对线性变换应用一次 tanh 激活函数处理,作为输出结果。
6.tf.split()
tf.split( value, num_or_size_splits, axis=0, num=None, name='split' )
value:准备切分的张量
num_or_size_splits:准备切成几份
axis : 准备在第几个维度上进行切割
其中分割方式分为两种
1. 如果num_or_size_splits 传入的 是一个整数,那直接在axis=D这个维度上把张量平均切分成几个小张量
2. 如果num_or_size_splits 传入的是一个向量(这里向量各个元素的和要跟原本这个维度的数值相等)就根据这个向量有几个元素分为几项)
7.tf.concat
tf.concat( values, axis, name='concat' ) #其实这和numpy中的np.concatenate()用法是一样的。
8.tf.nn.dynamic_rnn
tf.nn.dynamic_rnn(
cell,
inputs,
sequence_length=None,
initial_state=None,
dtype=None,
parallel_iterations=None,
swap_memory=False,
time_major=False, #inputs 和outputs 张量的形状格式。如果为True,则这些张量都应该是(都会是)[max_time,batch_size,depth.]。如果为false,则这些张量都应该是(都会是)[batch_size,max_time,depth]
scope=None
)
假设你的RNN的输入input是[2,20,128],其中2是batch_size,20是文本最大长度,128是embedding_size,可以看出,有两个example,我们假设第二个文本长度只有13,剩下的7个是使用0-padding方法填充的。dynamic返回的是两个参数:outputs,last_states,其中outputs是[2,20,128],也就是每一个迭代隐状态的输出,last_states是由(c,h)组成的tuple,均为[batch,128]。到这里并没有什么不同,但是dynamic有个参数:sequence_length,这个参数用来指定每个example的长度,比如上面的例子中,我们令 sequence_length为[20,13],表示第一个example有效长度为20,第二个example有效长度为13,当我们传入这个参数的时候,对于第二个example,TensorFlow对于13以后的padding就不计算了,其last_states将重复第13步的last_states直至第20步,而outputs中超过13步的结果将会被置零。
#coding=utf-8 import tensorflow as tf import numpy as np # 创建输入数据 X = np.random.randn(2, 10, 8) # 第二个example长度为6 X[1,6:] = 0 X_lengths = [10, 6] cell = tf.contrib.rnn.BasicLSTMCell(num_units=64, state_is_tuple=True) outputs, last_states = tf.nn.dynamic_rnn( cell=cell, dtype=tf.float64, sequence_length=X_lengths, inputs=X) result = tf.contrib.learn.run_n( {"outputs": outputs, "last_states": last_states}, n=1, feed_dict=None) print result[0] assert result[0]["outputs"].shape == (2, 10, 64) # 第二个example中的outputs超过6步(7-10步)的值应该为0 assert (result[0]["outputs"][1,7,:] == np.zeros(cell.output_size)).all()
9.tf.get_variable_scope().reuse_variables()
变量的命名空间是为了更好的管理和重用变量,因为神经网络的节点和参数非常多,我们需要scope来清楚的知道变量是那一层的。name_scope,实现变量共享的功能。
tf.placeholder,tf.Variable
,tf.get_variable三种方式创建变量。
(1)tf.placeholder(dtype, shape=None, name=None) 占位符。trainable==False,类似于函数的传递参数,在图运行前必须先传入值。
import tensorflow as tf input1 = tf.placeholder(tf.float32) input2 = tf.placeholder(tf.float32) output = input1 * input2 with tf.Session() as sess: print(sess.run(output, feed_dict = {input1:[3.], input2: [4.]}))
(2)
(3) tf.get_variable中变量名称是一个必填的参数,这个函数会根据这个名字常见或获取变量,如果创建失败(有同名的参数),那么程序就会报错,这是为了避免无意识的变量复用造成的错误
tf.get_variable(),在这个函数获取内部的参数。reuse的作用是在创建一个计算图时候,保证内部的变量可以通过。
tf.name_scope()
主要是用来管理命名空间的,这样子
让我们的整个模型更加有条理。
而 tf.variable_scope()
的作用是为了实现变量共享,它和tf.get_variable()
来完成变量共享的功能。
tf.name_scope()
可以和
with tf.variable_scope():
联合使用,用于给
非
get_variable
创建的变量
加上联合命名空间。
tf.trainable_variables()获取所有的可训练的变量,默认的是
tf.variable
和
tf.get_variable()
创建的。
import tensorflow as tf # 设置GPU按需增长 config = tf.ConfigProto() config.gpu_options.allow_growth = True sess = tf.Session(config=config) # 拿官方的例子改动一下 def my_image_filter(): conv1_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]), name="conv1_weights") conv1_biases = tf.Variable(tf.zeros([32]), name="conv1_biases") conv2_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]), name="conv2_weights") conv2_biases = tf.Variable(tf.zeros([32]), name="conv2_biases") return None # First call creates one set of 4 variables. result1 = my_image_filter() # Another set of 4 variables is created in the second call. result2 = my_image_filter() # 获取所有的可训练变量 vs = tf.trainable_variables() print 'There are %d train_able_variables in the Graph: ' % len(vs) for v in vs: print v >>There are 8 train_able_variables in the Graph: Tensor("conv1_weights/read:0", shape=(5, 5, 32, 32), dtype=float32) Tensor("conv1_biases/read:0", shape=(32,), dtype=float32) Tensor("conv2_weights/read:0", shape=(5, 5, 32, 32), dtype=float32) Tensor("conv2_biases/read:0", shape=(32,), dtype=float32) Tensor("conv1_weights_1/read:0", shape=(5, 5, 32, 32), dtype=float32) Tensor("conv1_biases_1/read:0", shape=(32,), dtype=float32) Tensor("conv2_weights_1/read:0", shape=(5, 5, 32, 32), dtype=float32) Tensor("conv2_biases_1/read:0", shape=(32,), dtype=float32)
为例避免重名,tf.get_variable() 可以使用scope.reuse_variables()来重用变量,除了使用这个函数还可以在with tf.variable_scope("image_filters",reuse=True) as scope:
中直接变量重用。
with tf.variable_scope("a_variable_scope") as scope: initializer = tf.constant_initializer(value=3) var3 = tf.get_variable(name='var3', shape=[1], dtype=tf.float32, initializer=initializer) scope.reuse_variables() var3_reuse = tf.get_variable(name='var3',) var4 = tf.Variable(name='var4', initial_value=[4], dtype=tf.float32) var4_reuse = tf.Variable(name='var4', initial_value=[4], dtype=tf.float32) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(var3.name) # a_variable_scope/var3:0 print(sess.run(var3)) # [ 3.] print(var3_reuse.name) # a_variable_scope/var3:0 print(sess.run(var3_reuse)) # [ 3.] print(var4.name) # a_variable_scope/var4:0 print(sess.run(var4)) # [ 4.] print(var4_reuse.name) # a_variable_scope/var4_1:0 print(sess.run(var4_reuse)) # [ 4.]
import tensorflow as tf # 创建一个新的计算图时候,reuse默认是None,也就是里面参数不可以复用, with tf.variable_scope('fin'): print(tf.get_variable_scope().reuse)# 查看当前图中的reuse参数的取值 with tf.variable_scope('foo',reuse=False): print(tf.get_variable_scope().reuse) tf.get_variable_scope().reuse_variables() print(tf.get_variable_scope().reuse) '''''' 输出如下 '''''' False False True
9.tf.contrib.layers.fully_connected
tf.contrib.layers.fully_connected( inputs, num_outputs, activation_fn=tf.nn.relu, normalizer_fn=None, normalizer_params=None, weights_initializer=initializers.xavier_initializer(), weights_regularizer=None, biases_initializer=tf.zeros_initializer(), biases_regularizer=None, reuse=None, variables_collections=None, outputs_collections=None, trainable=True, scope=None )
10.tf.contrib.layers.optimize_loss
tf.contrib.layers.optimize_loss( loss, global_step, #获取训练步数并在训练时更新 learning_rate, optimizer, gradient_noise_scale=None, gradient_multipliers=None, clip_gradients=None, learning_rate_decay_fn=None, update_ops=None, variables=None, name=None, summaries=None, colocate_gradients_with_ops=False, increment_global_step=True )
optimizer: 可以使用字符串,例如Adam
,但是必须要使用OPTIMIZER_CLS_NAMES。
OPTIMIZER_CLS_NAMES = { "Adagrad": train.AdagradOptimizer, "Adam": train.AdamOptimizer, "Ftrl": train.FtrlOptimizer, "Momentum": lambda learning_rate: train.MomentumOptimizer(learning_rate, momentum=0.9), "RMSProp": train.RMSPropOptimizer, "SGD": train.GradientDescentOptimizer, }
可以是一个使用learing_rate
作为参数,返回Optimizer一个实例的function。例如:
11.tf.train.get_global_step
12.tf.nn.rnn_cell.BasicLSTMCell
__init__( num_units, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None, name=None, dtype=None, **kwargs )
参数说明:
- num_units:int类型,LSTM单元中的神经元数量,即输出神经元数量
- forget_bias:float类型,偏置增加了忘记门。从CudnnLSTM训练的检查点(checkpoin)恢复时,必须手动设置为0.0。
- state_is_tuple:如果为True,则接受和返回的状态是c_state和m_state的2-tuple;如果为False,则他们沿着列轴连接。后一种即将被弃用。
- activation:内部状态的激活函数。默认为tanh
- reuse:布尔类型,描述是否在现有范围中重用变量。如果不为True,并且现有范围已经具有给定变量,则会引发错误。
- name:String类型,层的名称。具有相同名称的层将共享权重,但为了避免错误,在这种情况下需要reuse=True.
- dtype:该层默认的数据类型。默认值为None表示使用第一个输入的类型。在call之前build被调用则需要该参数。
DataFrame.shift(periods=1, freq=None, axis=0)
periods:类型为int,表示移动的幅度,可以是正数,也可以是负数,默认值是1,1就表示移动一次,注意这里移动的都是数据,而索引是不移动的,移动之后没有对应值的,就赋值为NaN。
freq: DateOffset, timedelta, or time rule string,可选参数,默认值为None,只适用于时间序列,如果这个参数存在,那么会按照参数值移动时间索引,而数据值没有发生变化。
axis:{0, 1, ‘index’, ‘columns’},表示移动的方向,如果是0或者’index’表示上下移动,如果是1或者’columns’,则会左右移动。
13.tf.gather
tf.gather( params, indices, validate_indices=None, name=None, axis=None, batch_dims=0 )
Args:
params
: ATensor
. The tensor from which to gather values. Must be at least rankaxis + 1
.indices
: ATensor
. Must be one of the following types:int32
,int64
. Index tensor. Must be in range[0, params.shape[axis])
.axis
: ATensor
. Must be one of the following types:int32
,int64
. The axis inparams
to gatherindices
from. Defaults to the first dimension. Supports negative indexes.batch_dims
: An optionalint
. Defaults to0
.name
: A name for the operation (optional).
Returns:
A Tensor
. Has the same type as params
.
import tensorflow as tf a = tf.Variable([[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15]]) index_a = tf.Variable([0,2]) b = tf.Variable([1,2,3,4,5,6,7,8,9,10]) index_b = tf.Variable([2,4,6,8]) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run(tf.gather(a, index_a))) print(sess.run(tf.gather(b, index_b))) # [[ 1 2 3 4 5] # [11 12 13 14 15]] # [3 5 7 9]
14.tf.sequence_mask
tf.sequence_mask( lengths, maxlen=None, dtype=tf.dtypes.bool, name=None )
tf.sequence_mask([1, 3, 2], 5) # [[True, False, False, False, False], # [True, True, True, False, False], # [True, True, False, False, False]] tf.sequence_mask([[1, 3],[2,0]]) # [[[True, False, False], # [True, True, True]], # [[True, True, False], # [False, False, False]]]
- lengths:整数张量,其所有值小于等于maxlen。
- maxlen:标量整数张量,返回张量的最后维度的大小;默认值是lengths中的最大值。
- dtype:结果张量的输出类型。
- name:操作的名字
解析1:maxlen是5,所以一共有5列,lengths有三个元素[1,2,3],所以有三行,每一行分别前1、2、3个元素为True;
解析2:因为没有指定maxlen,故maxlen默认取lengths中的最大值3,所以一共有3列,lengths是二维数组,将其看作由两个一维lengths组成,所以输出也可以看作由这两个一维lengths为2的输出所组成。
15.tf.nn.dropout
tf.nn.dropout( x, keep_prob, noise_shape=None, seed=None, name=None ) Defined in tensorflow/python/ops/nn_ops.py.
参数 keep_prob: 表示的是保留的比例,假设为0.8 则 20% 的数据变为0,然后其他的数据乘以 1/keep_prob;keep_prob 越大,保留的越多;
参数 noise_shape:干扰形状。 此字段默认是None,表示第一个元素的操作都是独立,但是也不一定。比例:数据的形状是shape(x)=[k, l, m, n],而noise_shape=[k, 1, 1, n],则第1和4列是独立保留或删除,第2和3列是要么全部保留,要么全部删除。
import os import numpy as np import tensorflow as tf x = tf.Variable(tf.ones([10, 10])) inputs = tf.nn.dropout(x, 0.8) init = tf.initialize_all_variables() with tf.Session() as sess: sess.run(init) print (x.eval()) print (inputs.eval())
输出的结果:
[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]] [[1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25] [1.25 1.25 0. 1.25 1.25 1.25 0. 0. 1.25 1.25] [1.25 1.25 0. 0. 1.25 0. 1.25 0. 1.25 1.25] [0. 1.25 1.25 0. 1.25 1.25 1.25 1.25 1.25 1.25] [1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 0. 1.25] [1.25 1.25 1.25 1.25 1.25 1.25 0. 1.25 0. 1.25] [1.25 0. 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25] [1.25 1.25 1.25 0. 0. 0. 1.25 0. 1.25 1.25] [1.25 1.25 1.25 1.25 1.25 1.25 0. 1.25 1.25 1.25] [1.25 1.25 1.25 0. 0. 1.25 0. 1.25 1.25 1.25]]
添加干扰项举例:
import os import numpy as np import tensorflow as tf x = tf.Variable(tf.ones([3,3,3])) inputs = tf.nn.dropout(x, 0.5,[3,1,3]) init = tf.initialize_all_variables() with tf.Session() as sess: sess.run(init) print (x.eval()) print (inputs.eval())
结果显示:
[[[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]] [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]] [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]]] --------------------------------- [[[2. 2. 2.] [2. 2. 2.] [2. 2. 2.]] [[0. 2. 2.] [0. 2. 2.] [0. 2. 2.]] [[0. 0. 2.] [0. 0. 2.] [0. 0. 2.]]]
结果解析:
-
keep_prob:设置神经元被选中的概率,在初始化时keep_prob是一个占位符, keep_prob = tf.placeholder(tf.float32) 。 tensorflow在run时设置keep_prob具体的值,例如keep_prob: 0.5。tensorflow中的dropout就是:使输入tensor中某些元素变为0,其它没变0的元素值变为原来的1/keep_prob大小!
效果图解:
有noise_shape的情况
a = tf.constant([[-1.0, 2.0, 3.0, 4.0, 5.0],[-1.0, 2.0, 3.0, 4.0, 5.0],[-1.0, 2.0, 3.0, 4.0, 5.0]]) with tf.Session() as sess: b = tf.nn.dropout(a, 0.5, noise_shape=[3,5]) print(sess.run(b)) 输出结果: [[-2. 0. 6. 8. 0.] [-2. 4. 0. 8. 10.] [-0. 0. 0. 0. 10.]] 结果解析:a的shape值是[3,5]和第一个b的noise_shape值一样,所以第1、2维都是独立的,可以看到第一个b的行之间的各列值都不一样。
with tf.Session() as sess: b = tf.nn.dropout(a, 0.9, noise_shape=[1,5]) print(sess.run(b)) 输出结果: [[-1.1111112 2.2222223 3.3333335 4.4444447 5.555556 ] [-1.1111112 2.2222223 3.3333335 4.4444447 5.555556 ] [-1.1111112 2.2222223 3.3333335 4.4444447 5.555556 ]] 结果解析: 第二个b中,noise_shape第1维为1和shape(a)不一致,所以第1维即行是相关的,3行的值是一样的;而列的值5=5,所以列的值可以不一样。
16.tf.gradients
tf.gradients( ys, xs, grad_ys=None, name='gradients', stop_gradients=None, )
1. xs和ys可以是一个张量,也可以是张量列表,tf.gradients(ys,xs) 实现的功能是求ys(如果ys是列表,那就是ys中所有元素之和)关于xs的导数(如果xs是列表,那就是xs中每一个元素分别求导),返回值是一个与xs长度相同的列表。例如ys=[y1,y2,y3], xs=[x1,x2,x3,x4],那么tf.gradients(ys,xs)=[d(y1+y2+y3)/dx1,d(y1+y2+y3)/dx2,d(y1+y2+y3)/dx3,d(y1+y2+y3)/dx4].具体例子见下面代码第16-17行。
2. grad_ys 是ys的加权向量列表,和ys长度相同,当grad_ys=[q1,q2,g3]时,tf.gradients(ys,xs,grad_ys)=[d(g1*y1+g2*y2+g3*y3)/dx1,d(g1*y1+g2*y2+g3*y3)/dx2,d(g1*y1+g2*y2+g3*y3)/dx3,d(g1*y1+g2*y2+g3*y3)/dx4].具体例子见下面代码第19-21行。
3. stop_gradients使得指定变量不被求导,即视为常量,具体的例子见官方例子
import tensorflow as tf
w1 = tf.Variable(tf.constant([[3,1]],tf.float32))
w2 = tf.Variable(tf.constant([[4,4]],tf.float32))
res = tf.matmul(w1, [[2.],[4.]])
with tf.Session() as sess:
tf.global_variables_initializer().run()
re = sess.run(grads)
print(re)
结果显示:
[array([[ 9., 10.]], dtype=float32)] #温馨提示,如果出现:TypeError: Fetch argument None has invalid type <class 'NoneType'>错误信息,tensorflow梯度值一般都是float32类型的。所以我们修改代码将整型的张量改为浮点型。第二个参数为求导参数,如果求梯度的式子中没有要求偏导的变量,系统会报错。
17.tf.varable
reuse有三种取值,默认取值是None:
True: 参数空间使用reuse 模式,即该空间下的所有tf.get_variable()函数将直接获取已经创建的变量,如果参数不存在tf.get_variable()函数将会报错。
AUTO_REUSE:若参数空间的参数不存在就创建他们,如果已经存在就直接获取它们。
None 或者False 这里创建函数tf.get_variable()函数只能创建新的变量,当同名变量已经存在时,函数就报错
able_scope 参数。
18.padded_batch
padded_batch( batch_size, padded_shapes, padding_values=None, drop_remainder=False )
参数padded_shapes #指明每条记录中各成员要pad成的形状,成员若是scalar,则用[],若是list,则用[mx_length],若是array,则用[d1,...,dn],假如各成员的顺序是scalar数据、list数据、array数据,则padded_shapes=([], [mx_length], [d1,...,dn]);
padding_values
: (Optional.) A nested structure of scalar-shaped tf.Tensor
, representing the padding values to use for the respective components. Defaults are 0
for numeric types and the empty string for string types.
19.tf.TensorShape
__init__(dims)
Creates a new TensorShape with the given dimensions.
Args:
dims
: A list of Dimensions, or None if the shape is unspecified.
A TensorShape
represents a possibly-partial shape specification for a Tensor
. It may be one of the following:
Fully-known shape: has a known number of dimensions and a known size for each dimension. e.g. TensorShape([16, 256])
- Partially-known shape: has a known number of dimensions, and an unknown size for one or more dimension. e.g.
TensorShape([None, 256])
- Unknown shape: has an unknown number of dimensions, and an unknown size in all dimensions. e.g.
TensorShape(None)
20.tf.train.get_checkpoint_state
tf.train.get_checkpoint_state(checkpoint_dir,latest_filename=None) #通过checkpoint文件找到模型文件名
案例代码:
with tf.Session() as sess: ckpt=tf.train.get_checkpoint_state('Model/') print(ckpt) if ckpt and ckpt.all_model_checkpoint_paths: #加载模型 #这一部分是有多个模型文件时,对所有模型进行测试验证 for path in ckpt.all_model_checkpoint_paths: saver.restore(sess,path) global_step=path.split('/')[-1].split('-')[-1] accuracy_score=sess.run(accuracy,feed_dict=validate_feed) print("After %s training step(s),valisation accuracy = %g"%(global_step,accuracy_score)) ''' #对最新的模型进行测试验证 saver.restore(sess,ckpt.model_checkpoint_paths) global_step=ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1] accuracy_score=sess.run(accuracy,feed_dict=validate_feed) print("After %s training step(s),valisation accuracy = %g"%(global_step,accuracy_score)) ''' else: print('No checkpoint file found') return #time.sleep(eval_interval_secs) return
结果输出: