TF的核心数据单位是张量,张量由一组形成阵列的原始数据组成,张量的阶是它的维数,而它的维数是一哥整数元组,指定了阵列的每个维度的长度:
(1) 构建计算图(tf.Graph)
(2) 运算计算图(tf.Session)
计算图是排列成一个图的一系列TF指令,图由两种类型的对象组成
指令:图的节点。指令说明的是消耗和生成张量的计算。 张量:图的边。它们代表将流经图的值。大多数会返回tf.Tensor最基本的指令是一个常量。构建指令的Python函数将一个张量值作为输入值。生成的指令不需要输入值。它在运行时输出的是被传递给构造函数的值。我们创建两个浮点数常量a和b:
a = tf.constant(3.0,dtype = tf.float32) b = tf.constant(4.0) total = a+b print (a) print (b) print (total)打印语句会生成:
Tensor("Const: 0",shape=(),dtype = float32) Tensor("Const_1: 0",shape=(),dtype =float32) Tensor("add:0",shape =(),dtype =float32)图中每个张量都拥有唯一的名称。这个名称不同于使用的Python分配给对应的对象的名称。张量是根据生成它们的指令命名的,后面跟着输出索引。
Tensorboard能够使计算图可视化。其过程如下:
(1)将计算图保存为Tnesorboard摘要文件,具体操作如下:
writer = tf.summary.FileWriter('.') writer.add_graph(tf.get_default_graph())这将在当前目录中生成一个event文件,其名称格式如下
events.out.tfevents.{timestamp}.{hostname}
在终端使用shell命令,启动TensorBoard
tensorboard --logdir接下来在浏览器打开TnesorBoard的图页面,你应该看到计算图如下所示:
要评估张量,需要实例化一个tf.Session对象(会话)。会话会封装TensorFlow运行时的状态,并运行TF指令。如果tf.Graph像一个.py文件,那么tf.Session就像一个可执行的python
以下创建一个tf.Session对象,然后调用其run方法来评估我们在上文中创建的total张量:
sess = tf.Session() print (sess.run(total))当使用Session.run请求输出节点时,TF会回溯整个图,并流经提供了所请求的输出节点对应的输入值的所有节点,因此指令会打印出预期值。
也可以将多个张量传递给tf.Session.run。run方法以透明方式处理元组或字典的任何组合,如下例
print (sess.run('ab':(a,b),'total':total))它返回的结果有相同的布局:
{‘total’:7.0,'ab':(3.0,4.0)}上面的图只能产生一个常量的结果,图可以参数化以便接收外部输入,也称为占位符。占位符表示承诺在稍后提供值,它就行函数参数:
x = tf.placeholder(tf.float32) y = tf.placeholder(tf.float32) z = x + y前三行有点像函数。我们定义了这个函数的两个输入参数(x和y),然后对它们运行指令。我们可以使用run方法的feed_dict参数来为占位符提供真正的值,从而通过多个输入值来评估这个图:
print (sess.run(z,feed_dict ={x:3,y:4,5})) print (sess.run(z,feed_dict={x:[1,3],y:[2,4]}))输出结果为:
7.5 [3.,7.]注意,feed_dict参数可以用于覆盖图中的任何张量。占位符和其他tf.Tensors的唯一不同之处在于如果没有提供值给他们,那么占位符会显示错误。
占位符适用于简单实验,但数据集是将数据流形式传递到模型的首选方法。
要从数据集中获取可运行的tf.Tensor,必须现将其转换成tf.data.Iterater,然后调用迭代器的get_next方法。
创建迭代器的最简单的方法方式是采用make_one_shot_iterator方法。例如,在下面的代码中,next_item张量将在每次run调用时从my_data阵列返回一行:
my_data = [ [0,1], [2,3], [4,5], [6,7], ] slices = tf.data.Dataset.from_tensor_slices(my_data) next_item = slices.make_one_shot_iterator().get_next()到达数据流末端是,Dataset会抛出OutOfRangeError。例如,下面代买会一直读取next_item,直到没有数据可读:
while True: try: print(sess.run(next_item)) except tf.errors.OutOfRangeError: break可训练的模型必须修改图中的值,以便在相同输入值的情况下获得新的输出值。将可训练的参数添加到图中的首选方式是层。
层将变量和作用于他们的指令打包在一起。例如,密集连接层会对每个输出值对应的所有输入值执行加权和,并应用可选择的激活函数。连接权重和偏差由层对象管理。
下面会创建一个Dense层,该层会接收一批输入矢量,并为每个矢量生成单一的输出值。要将层应用于输入值,请将该层当做函数来调用。例如
x = tf.placeholder(tf.float32,shape = [None,3]) linear_model =tf.layer.Dense(units=1) y = linear_model(x)层会检查其输入数据,以确定其内部变量的大小。因此,我们必须在这里设置x占位符的形状,以便层构建正确大小的权重矩阵。
在定义完图后,还有一个细节需要处理(初始化)
层包含的变量必须先初始化,然后才能使用。如下所示:
init = tf.global_variables_initializer() sess.run(init)此global_variables_initializer仅会初始化创建初始化程序是图中就存在的变量。因此应该在构建图标的最后一步添加初始化程序。
我们现在已经完成了层的初始化,可以像处理任何其他张量一样评估linear_model的输出张量了。例如:
print (sess.run(y,x:{[1,2,3],[4,5,6]}))会生成一个两元素向量,如下所示:
[[-3.413478999] [-9.149999908]]对于每个层类别(如tf.layers.Dense),TF还提供了一个快捷函数(如tf.layers.dense)。两者唯一的区别是快捷函数版本是在单次调用中创建和运行层。例如:
x = tf.placeholder(tf.float32,shape=[None,3]) y = tf.layers.dense(x,units=1) init = tf.global_variables_initializer() sess.run() print (sess.run(y,{x:[[1,2,3],[4,5,6]]})) 尽管这种方法很方便,但无法访问 tf.layers.Layer 对象。这会让自省和调试变得更加困难,并且无法重复使用相应的层。使用特征列进行试验的最简单方式是使用tf.feature_column.input_layer函数。此函数只接受密集列作为输入数据,因此要查看分类列的结果,你必须将其包含在tf.feature_column.indicator_column。例如:
features = { 'sales': [[5],[10],[8],[9]] 'department':['sports','sports','gardening','gardening]} department_column = tf.feature_column.categorical_column_with_vocabulary_list('department',['sports','gardening']) department_column = tf.feature_column.indicator_column(department_column) columns = [tf.feature_column.numeric_column('sales'),department_column] inputs = tf.feature_column.input_layer(features,columns)运行inputs张量会将features解析为一批向量
特征列和层一样具有内部状态,因此通常需要将他们初始化。分类列会在内部使用对照表,而这些表需要单独的初始化指令tf.tables_initializer
var_init = tf.global_variables_initializer() table_init = tf.tables_initalizer() sess = tf.Session() sess.run(var_init,table_init)内部状态初始化完成后,可以像运行任何其他tf.Tensor一样运行inputs:
print (sess.run(inputs))这显示了特征列如何打包输入矢量,在这个过程中,独热“部门”被用作第一和第二索引,“销售”用作第三个。
[[ 1. 0. 5.] [ 1. 0. 10.] [ 0. 1. 8.] [ 0. 1. 9.]]1、定义数据
首先定义一些输入值x,以及每个输入值的预期输出值y_true
x = tf.constant([[1],[2],[3],[4]],dtype = tf.float32) y_ture = tf.constant([[0],[-1],[-2],[-3]],dtype = tf.float32)2、定义模型
接下来,定义一个简单的线性模型,其输出值只1个
linear_model=tf.layers.Dense(units=1) y_pred = linear_model(x)可以如下评估预测值:
sess= tf.Session() init = tf.global_variables_initializers() sess.run() print (sess.run(y_pred))模型尚未接受训练,预测值并不理想
3、损失
要优化模型,首先要定义损失,我们将适应均方误差,这是回归问题的标准损失
tf.losses提供了一系列常用损失函数,可以使用它来计算均方误差
loss = tf.losses.mean_squared_error(labels=y_true,predictions =y_pred) print (sess.run(loss))将会生成一个损失
4、训练
TF也提供了优化器啦执行标准的优化算法,这些优化器被用作tf.train.Optimizer的子类别。他们会逐渐改变每个变量,使损失最小化。最简单的优化算法是梯度下降法。可以通过tf.train.GradientDescentOptimizer执行。他会根据损失相对于变量的导数大小来修改各个变量。
optimizer = tf.train.GradientDescentOptimizer(0.01) train = optimizer.minimize(loss)该代码构建了优化所需要的所有图组件,并返回一个训练指令。该指令在运行时会更新图中的变量。可如下运行该指令:
for i in range(100): _,loss_value =sess.run((train,loss)) print (loss_value)由于train是一个指令而不是张量,因此在她运行时不会返回一个值。为了查看训练期间损失的进展,我们会同时运行损失张量,生如下损失值:
1.356591.004120.7591670.5888290.4702640.3876260.3299180.2895110.2611120.241046完整程序
x = tf.constant([[1], [2], [3], [4]], dtype=tf.float32)y_true = tf.constant([[0], [-1], [-2], [-3]], dtype=tf.float32)linear_model = tf.layers.Dense(units=1)y_pred = linear_model(x)loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)optimizer = tf.train.GradientDescentOptimizer(0.01)train = optimizer.minimize(loss)init = tf.global_variables_initializer()sess = tf.Session()sess.run(init)for i in range(100): _, loss_value = sess.run((train, loss)) print(loss_value)print(sess.run(y_pred))