TensorFlow提供了大量的规约计算函数,比如tf.reduce_max(),tf.reduce_min(),tf.reduce_sum()等,这里我们仔细看一下tf.reduce_mean()。
函数定义如下:
tf.reduce_mean(input_tensor,reduction_indices=None,keep_dims=False,name=None)
该函数用于对输入的Tensor求取均值,如果不给定reduction_indices的话,就默认为对整个Tensor求取均值,而如果reduction_indices=0,则表示对第一维的元素取均值,即每一列求平均值;reduction_indices=1,则为对第二维的元素取平均值,即每一行求平均值。下面我们举例进行说明:
import tensorflow as tf
import numpy as np
sess=tf.InteractiveSession()
v=np.array([1,2,3,4])
x=tf.constant(v,dtype=tf.float32,shape=[2,2])
print tf.reduce_mean(x).eval()
print tf.reduce_mean(x,0).eval()
print tf.reduce_mean(x,1).eval()
运行结果:
从上面的运行结果可以看出来,该函数默认对整个Tensor求取均值,如果传入reduction_indices=0,则对列求取均值,如果传入reduction_indices=1,则对行求取均值。
突然发现TensorFlow也并不是一味地需要自己去构建神经网络层,比如全连接层,我们也可以使用TensorFlow提供的dense来实现,而非自己声明W和b,然后利用op来实现。
在core.py中定义了全连接层Dense类和正则化层Dropout类,我们可以通过core.py文件中的dense()和dropout()函数接口对此进行调用。用起来还挺方便的,和tflearn差不多,可以参考全连接层。
dense函数的签名如下:
dense(inputs,units,activation=None,use_bias=True,kernel_initialize=None,bias_initializer=init_ops.zeros_initializer(),kernel_regularizer=None,bias_regularizer=None,activity_regularizer=None,trainable=True,name=None,reuse=None)
TFLearn中的fully_connected函数签名如下:
fully_connected(incoming,n_units,activation='linear',bias=True,weights_init='truncated_normal',bias_init='zeros',regularzer=None,weight_decay=0.001,trainable=True,name='FullyConnected')
下面我们对dense函数的使用进行举例:
import tensorflow as tf
import numpy as np
sess=tf.InteractiveSession()
x=tf.placeholder(dtype=tf.float32,shape=[None,3])
net=tf.layers.dense(x,5)
y=tf.layers.dense(net,1)
sess.run(tf.global_variables_initializer())
inputs=[[1,2,3],[4,5,6]]
print sess.run(y,feed_dict={x: inputs})
TensorFlow可视化是使用summary和tensorboard合作完成的,这里的summary也是一个op。
首先,我们来看如何输出网络结构:
import tensorflow as tf
with tf.Session() as sess:
x=tf.placeholder(dtype=tf.float32,shape=[None,3])
net=tf.layers.dense(x,5)
y=tf.layers.dense(net,1)
writer=tf.summary.FileWriter('/home/moran/DRL/visualization',sess.graph)
运行完成之后,会将sess.graph保存到指定目录下:
此时我们在命令行运行tensorboard --logdir /home/moran/DRL/visualization,然后在浏览器中输入127.0.1.1 : 6006(tf1.1.0版本换为了0.0.0.0:6006):
下面我们介绍数据序列化:
TensorBoart通过读取TensorFlow的事件文件来运行。TensorFlow的事件文件包括了我们会在TensorFlow运行中涉及到的主要数据。下面介绍一下TensorBoard中汇总数据(Summary data)的大体生命周期。
首先,创建你想要汇总数据的TensorFlow图,然后选择我们想要在哪个节点进行汇总(summary)操作。
比如,我们正在训练一个卷积神经网络,用于识别MNIST标签,我们可能希望记录学习速度如何变化以及目标函数如何变化,通过向节点添加scalar_summary操作来分别输出学习速度和期望误差,然后我们可以给每个scalar_summary分配一个有意义的标签,比如'learning rate'和'loss function'。
或者,我们还希望显示一个特殊层中激活(activations)的分布,或者梯度权重的分布,可以通过分别附加histogram_summary运算来收集权重变量和梯度输出。
所有可用的summary操作详细信息,可以看summary_operation文档。
在TensorFlow中,所有的操作只有当你执行,或另一个操作依赖于它的输出时才会运行。我们刚才创建的这些节点(summary nodes)都围绕着我们的图像:没有任何操作依赖于它们的结果。因此,为了生成汇总信息,我们需要运行所有的节点,这样的工作很乏味,不过可以使用tf.merge_all_summaries来将它们合为一个操作。
我们执行合并命令,它会将所有的数据生成一个序列化的Summary protobuf对象。最后,为了将汇总数据写入磁盘,需要将汇总的protobuf对象传递给tf.train.Summarywriter。
SummaryWriter的构造函数中包含了参数 logdir。这个 logdir 非常重要,所有事件都会写到它所指的目录下。此外,SummaryWriter中还包含了一个可选择的参数GraphDef。如果输入了该参数,那么 TensorBoard 也会显示我们的图像。
现在已经修改了我们的图,也有了SummaryWriter,现在就可以运行我们的神经网络了!如果愿意的话,我们可以每一步执行一次合并汇总,这样将会得到一大堆训练数据。这很有可能超过了我们想要的数据量。我们也可以每一百步执行一次合并汇总,或者如下面代码里示范的这样。
merged_summary_op = tf.merge_all_summaries()
summary_writer = tf.train.SummaryWriter('/tmp/mnist_logs', sess.graph)
total_step = 0
while training:
total_step += 1
session.run(training_op)
if total_step % 100 == 0:
summary_str = session.run(merged_summary_op)
summary_writer.add_summary(summary_str, total_step)
值得注意的是,函数的具体写法依版本而定,比如tf.merge_all_summaries(old)和tf.summary.merge_all(new),tf.train_SummaryWriter(old)和tf.summary.FileWriter(new),这是一定要注意的。
现在已经准备好用 TensorBoard 来可视化这些数据了。
首先启动TensorBoard:
python tensorflow/tensorboard/tensorboard.py --logdir=path/to/log-directory
此外,如果我们已经利用pip安装了TensorBoard,那么我们可以执行更为简单的命令来访问TensorBoard:
tensorboard --logdir=/path/to/log-directory
进入TensorBoart界面时,我们会在右上角看见导航的选项卡,每一个选项卡将展现一组可视化的序列化数据集。对于我们查看的每一个选项卡,如果TensorBoard中没有数据与这个选项卡相关的话,则会显示一条提示信息指示我们如何序列化相关数据。
更多说明请参考:TensorBoard图标可视化。
最后,具体介绍几个函数:
1)tf.summary.merge_all:将之前定义的所有summary op整合到一起;
2)FileWriter:创建一个file writer用于向硬盘写summary数据;
3) tf.summary.scalar(summary_tags, Tensor/variable, collections=None):用于标量的summary;
4) tf.summary.histogram(tag, values, collections=None, name=None):生成直方图summary;
注意到其中的collections参数,它是一个list,如果不指定collections,那么这个summary将会被添加到tf.GraphKey.SUMMARIES中,如果指定了,就会被放在collections中。
对了,上面的add_summary仅仅是向FileWriter对象的缓存中存放event data,而向disk上写数据是由FileWriter对象控制的。
注意:
1)如果使用writer.add_summary(summary,global_step)时没有传global_step参数,会使得scalar_summary变为一条直线;
2)只要是在计算图上面 的summary op,都会被merge_all捕获,不需要考虑变量的生存期空间问题;
3)如果执行一次,disk上没有保存summary数据的话,可以尝试一下file_writer.flush()。
4)如果想要生成的summary有层次的话,记得在summary外面加一个name_scope:
with tf.name_scope("summary_gradients"):
tf.summary.histogram("name",gradients)