人工智能 - 模型可视化 TensorBoard [4]

欢迎Follow我的GitHub,关注我的简书

在训练模型的过程中,经常需要调试其中的参数,这就需要可视化。TensorFlow的可视化由TensorBoard完成,由TensorBoard显示已存储的Log信息。代码与多层感知机的MNIST相同,只是添加一些Log信息的存储,用于展示。

本文源码的GitHub地址,位于tensor_board文件夹。

执行TensorBoard的命令:

tensorboard --logdir=/tmp/tensorflow/mnist/logs/mnist_with_summaries

显示网站在Log信息中,如http://0.0.0.0:6006

Starting TensorBoard 47 at http://0.0.0.0:6006
(Press CTRL+C to quit)
WARNING:tensorflow:path ../external/data/plugin/text/runs not found, sending 404
WARNING:tensorflow:path ../external/data/plugin/text/runs not found, sending 404
WARNING:tensorflow:path ../external/data/plugin/text/runs not found, sending 404
WARNING:tensorflow:path ../external/data/plugin/text/runs not found, sending 404
TensorBoard

显示日志

设置参数,使用argparse.ArgumentParser()创建参数解析器nargs='?' + const=True + default=False表示:当使用--fake_data时,参数的fake_data的值是True(const);当未使用--fake_data时,参数的fake_data的值是False(default);或者指定--fake_data True(Flase),根据设置的参数赋值。type是参数类型,help是帮助信息。获取os.getenv('TEST_TMPDIR', '/tmp')临时文件夹,默认是/tmp,在Mac中是根目录下的隐藏文件夹。os.path.join将文件夹的路径拼接在一起。

parser = argparse.ArgumentParser()
parser.add_argument('--fake_data', nargs='?', const=True, type=bool, default=False,
                    help='If true, uses fake data for unit testing.')
parser.add_argument('--max_steps', type=int, default=1000,  # 最大步数 1000
                    help='Number of steps to run trainer.')
parser.add_argument('--learning_rate', type=float, default=0.001,  # 学习率 0.001
                    help='Initial learning rate')
parser.add_argument('--dropout', type=float, default=0.9,  # Dropout的保留率 0.9
                    help='Keep probability for training dropout.')
parser.add_argument('--data_dir', type=str,  # 数据目录
                    default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'), 'tensorflow/mnist/input_data'),
                    help='Directory for storing input data')
parser.add_argument('--log_dir', type=str,  # Log目录
                    default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'),
                                         'tensorflow/mnist/logs/mnist_with_summaries'),
                    help='Summaries log directory')

在外部声明FLAGS变量,将参数放入FLAGS中,使用tf.app.run()执行TensorFlow的脚本,main是入口方法,argv是参数。

FLAGS = None  # 外部声明

FLAGS, unparsed = parser.parse_known_args()
tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

调用tf.gfile文件处理库,如果日志文件夹存在,则删除,并重建,然后执行核心方法train()。

def main(_):
    if tf.gfile.Exists(FLAGS.log_dir):
        tf.gfile.DeleteRecursively(FLAGS.log_dir)
    tf.gfile.MakeDirs(FLAGS.log_dir)
    train()

加载数据,使用MNIST数据源,创建可交互的Session,即tf.InteractiveSession(),张量可以自己执行操作。

mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True, fake_data=FLAGS.fake_data)  # 加载数据
sess = tf.InteractiveSession()

需要输入的PlaceHolder,指定命名空间input,在绘制流程图的时候使用;将输入数据转换为图像,并且保持在input_reshape/input文件夹中,图片命名规则为input_reshape/input/image/#

# Input placeholders
with tf.name_scope('input'):  # 指定命名空间
    x = tf.placeholder(tf.float32, [None, 784], name='x-input')
    y_ = tf.placeholder(tf.float32, [None, 10], name='y-input')
    
with tf.name_scope('input_reshape'):
    image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
    tf.summary.image('input', image_shaped_input, 10)  # 10表示只存储10张
name_scope
Image

将创建权重和偏移变量的方法设置为方法。

# We can't initialize these variables to 0 - the network will get stuck.
def weight_variable(shape):  # 权重
    """Create a weight variable with appropriate initialization."""
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def bias_variable(shape):  # 偏移
    """Create a bias variable with appropriate initialization."""
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

变量信息的存储方法,存储为标量(tf.summary.scalar),或者直方图(tf.summary.histogram)。

def variable_summaries(var):  #
    """Attach a lot of summaries to a Tensor (for TensorBoard visualization)."""
    with tf.name_scope('summaries'):
        mean = tf.reduce_mean(var)  # 均值
        tf.summary.scalar('mean', mean)
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        tf.summary.scalar('stddev', stddev)
        tf.summary.scalar('max', tf.reduce_max(var))  # 标量
        tf.summary.scalar('min', tf.reduce_min(var))
        tf.summary.histogram('histogram', var)  # 直方图

偏移biases的初始值均为0.1,通过学习逐渐变化。

Scalar

偏移biases的初始值均为0.1,每一次迭代使得分布越来越平缓。

Hist

神经网络的层次,使用y=wx+b的线性回归,并且记录下参数W和b的信息,还有使用激活函数前后的数据对比情况。

def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
    """Reusable code for making a simple neural net layer.
    
    It does a matrix multiply, bias add, and then uses ReLU to nonlinearize.
    It also sets up name scoping so that the resultant graph is easy to read,
    and adds a number of summary ops.
    """
    # Adding a name scope ensures logical grouping of the layers in the graph.
    with tf.name_scope(layer_name):
        # This Variable will hold the state of the weights for the layer
        with tf.name_scope('weights'):
            weights = weight_variable([input_dim, output_dim])
            variable_summaries(weights)
        with tf.name_scope('biases'):
            biases = bias_variable([output_dim])
            variable_summaries(biases)
        with tf.name_scope('Wx_plus_b'):
            preactivate = tf.matmul(input_tensor, weights) + biases
            tf.summary.histogram('pre_activations', preactivate)  # 未激活的直方图
        activations = act(preactivate, name='activation')
        tf.summary.histogram('activations', activations)  # 激活的直方图
        return activations

由于第一层使用ReLU(校正线性单元,Rectified Linear Unit),将小于0的值,全部抑制为0。

ReLU

第一层是ReLU激活函数,第二次未使用激活函数(tf.identity),并且将第一层的神经元dropout,训练小于1,测试等于1。

hidden1 = nn_layer(x, 784, 500, 'layer1')  # 隐藏层

with tf.name_scope('dropout'):
    keep_prob = tf.placeholder(tf.float32)
    tf.summary.scalar('dropout_keep_probability', keep_prob)
    dropped = tf.nn.dropout(hidden1, keep_prob)  # 执行dropout参数
    
# Do not apply softmax activation yet, see below.
y = nn_layer(dropped, 500, 10, 'layer2', act=tf.identity)  # 未使用激活函数

损失函数设置为交叉熵,使用AdamOptimizer优化损失函数,并且记录损失函数的值,逐渐收敛。

with tf.name_scope('cross_entropy'):
    diff = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)
    with tf.name_scope('total'):
        cross_entropy = tf.reduce_mean(diff)
tf.summary.scalar('cross_entropy', cross_entropy)

with tf.name_scope('train'):
    train_step = tf.train.AdamOptimizer(FLAGS.learning_rate).minimize(
        cross_entropy)
Loss

准确率,比较正确的个数,求平均,并使用标量记录(tf.summary.scalar)。

with tf.name_scope('accuracy'):
    with tf.name_scope('correct_prediction'):
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    with tf.name_scope('accuracy'):
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.summary.scalar('accuracy', accuracy)

将每次迭代的summary合并成一个文件,并且创建两个writer,一个用于训练,一个用于测试,同时训练的存储图信息。

merged = tf.summary.merge_all()
train_writer = tf.summary.FileWriter(FLAGS.log_dir + '/train', sess.graph)
test_writer = tf.summary.FileWriter(FLAGS.log_dir + '/test')

计算图信息的节点,就是最顶层的name_scope,点击之后就是内部的name_scope

Graph

设置feed数据的接口,训练使用批次数据,每次100个,dropout是参数;测试使用全部的测试数据,dropout是1,保留全部信息。

def feed_dict(train):
    """Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
    # 训练与测试的dropout不同
    if train or FLAGS.fake_data:
        xs, ys = mnist.train.next_batch(100, fake_data=FLAGS.fake_data)
        k = FLAGS.dropout
    else:
        xs, ys = mnist.test.images, mnist.test.labels
        k = 1.0
    return {x: xs, y_: ys, keep_prob: k}

初始化变量,开始迭代执行。每隔10次,使用测试集验证一次,sess.run()的输入,merged合并的Log信息,accuracy计算图,feed数据,将信息写入test_writer。每隔99步,将运行时间与内存信息,存入Log中,其余步骤正常秩序,添加存储信息。

tf.global_variables_initializer().run()

for i in range(FLAGS.max_steps):
    if i % 10 == 0:  # Record summaries and test-set accuracy
        summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False))  # feed测试数据
        test_writer.add_summary(summary, i)
        print('Accuracy at step %s: %s' % (i, acc))
    else:  # Record train set summaries, and train
        if i % 100 == 99:  # Record execution stats
            run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
            run_metadata = tf.RunMetadata()
            summary, _ = sess.run([merged, train_step],  # feed训练数据
                                  feed_dict=feed_dict(True),
                                  options=run_options,
                                  run_metadata=run_metadata)
            train_writer.add_run_metadata(run_metadata, 'step%03d' % i)
            train_writer.add_summary(summary, i)
            print('Adding run metadata for', i)
        else:  # Record a summary
            summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True))  # feed训练数据
            train_writer.add_summary(summary, i)

最后注意关闭Log文件写入器

train_writer.close()
test_writer.close()

内存与计算时间

Runtime

在安装TensorFlow后,TensorBoard即可使用,但是在mac系统中,会报错,由于six包的版本过低导致。

  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/six.py", line 566, in with_metaclass
    return meta("NewBase", bases, {})
  File "/Library/Python/2.7/site-packages/tensorflow/python/platform/benchmark.py", line 116, in __new__
    if not newclass.is_abstract():
AttributeError: type object 'NewBase' has no attribute 'is_abstract'

在Mac系统中,含有多个Python源,我们要确定shell使用的源

➜  ~ python
Python 2.7.10 (default, Oct 23 2015, 19:19:21)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import six
>>> six.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/six.pyc'

升级指定位置的six包

sudo pip install six --upgrade --target="/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/"

当然,最简单的就是直接使用虚拟环境的TensorBoard,库的版本可控。


OK, that's all! Enjoy it!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容