tensorflow 1.3 tips - 2

#60 · open · 39 comments

View on GitHub ↗

leftrk

**正则化** ```python weights = tf.constant([[1.0, -2.0], [-3.0, 4.0]]) with tf.Session() as sess: # 输出为(|1| + |-2| + |-3| + |4|) * 0.5 = 5,其中0.5为正则化项的权重 print(sess.run(tf.contrib.layers.l1_regularizer(.5)(weights))) # 输出为(1^2 + (-2)^2 + (-3)^2 + 4^2/2) * 0.5 = 7.5,TF会将L2的正则化损失值除以2使得求导更简洁 print(sess.run(tf.contrib.layers.l2_regularizer(.5)(weights))) ```

Comments

leftrk

```python # b. 损失函数 # 计算交叉熵及其平均值 # 目标类别只有一个正确答案时可使用tf.nn.sparse_softmax_cross_entropy_with_logits来加速交叉熵计算 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, axis=1)) # 计算当前batch中所有样例的交叉熵平均值 cross_entropy_mean = tf.reduce_mean(cross_entropy) # 计算L2正则化损失,一般只计算权重部分,不使用偏置项 regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE) regularaztion = regularizer(weights1) + regularizer(weights2) # 总的损失函数 loss = cross_entropy_mean + regularaztion ````

leftrk

```python global_step = tf.Variable(0, trainable=False) # 给定滑动平均衰减率、训练轮数,初始化滑动平均类。给定训练轮数可以加快训练早期变量的更新速度 variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step) # 在所有代表神经网络参数的变量上使用滑动平均:即Graphkeys.TRAINABLE_VARIABLES中的元素,也即所有没有指定trainable=False的参数 variables_averages_op = variable_averages.apply(tf.trainable_variables()) # 滑动平均不会改变变量本身取值,只是维护一个影子变量来记录其滑动平均值,因此需要使用这个滑动平均值时需要明确调用average函数 average_y = inference(x, variable_averages, weights1, biases1, weights2, biases2) ```

leftrk

```python # c. 反向传播 # 设置指数衰减的学习率。 learning_rate = tf.train.exponential_decay( LEARNING_RATE_BASE, global_step, mnist.train.num_examples / BATCH_SIZE, LEARNING_RATE_DECAY, staircase=True) ```

leftrk

```python # 优化损失函数(更新神经网络参数) train_step = tf.train.GradientDescentOptimizer(learning_rate) .minimize(loss, global_step=global_step) ```

leftrk

```python # 每一遍训练,反向传播既需要更新参数,也需要更新每一个参数的滑动平均值 # train_op = tf.group(train_step, variables_average_op)等价下面两行 with tf.control_dependencies([train_step, variables_averages_op]): train_op = tf.no_op(name='train') ```

leftrk

```python # 另;检验使用了滑动平均模型的神经网络前向传播是否正确 # tf.equal判断两个张量的每一维是否相等,返回True/False correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_, 1)) # tf.cast转换数据类型,这里将布尔型转换成实数型 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) ```

leftrk

```python def inference(input_tensor, reuse=False): # 定义第一层神经网络的变量和前向传播过程 with tf.variable_scope('layer1', reuse=reuse): # 根据传进来的reuse判断创建新变量还是使用已创建好的。第一次构造网络时需要创建新的,以后每次调用都使用reuse=True就不需要每次传递变量进来 weights = get_weight_variable([INPUT_NODE, LAYER1_NODE], initializer=tf.truncated_normal_initializer(stddev=0.1)) biases = tf.get_variable("biases", [LAYER1_NODE], initializer=tf.constant_initializer(0.0)) layer1 = tf.nn.relu(tf.matmul(input_tensor, weights) + biases) # 定义第二层神经网络的变量和前向传播过程 with tf.variable_scope('layer2', reuse=reuse): weights = get_weight_variable([LAYER1_NODE, OUTPUT_NODE], initializer=tf.truncated_normal_initializer(stddev=0.1)) biases = tf.get_variable("biases", [OUTPUT_NODE], initializer=tf.constant_initializer(0.0)) layer2 = tf.matmul(layer1, weights) + biases # 返回最后的前向传播结果 return layer2 ```

leftrk

```python # 声明tf.train.Saver类用于保存模型 saver = tf.train.Saver() with tf.Session() as sess: sess.run(init_op) saver.save(sess, "Saved_model/model.ckpt") ```

leftrk

```python # 该类可以读取checkpoint文件中保存的所有变量,注意后面的.data和.index可以省去 reader = tf.train.NewCheckpointReader('Saved_model/model.ckpt') # 获取所有变量列表,这个是一个从变量名到变量维度的字典 global_varibales = reader.get_variable_to_shape_map() for variable_name in global_varibales: # variable_name为变量名称,global_variables[variable_name]为变量的维度 print(variable_name, global_varibales[variable_name]) # 获取名为v1的变量的取值 print("Value for variable v1 is ", reader.get_tensor("v1")) ```

leftrk

```python saver = tf.train.Saver() with tf.Session() as sess: # 加载已经保存的模型,并通过已保存的模型中变量来计算加法 saver.restore(sess, "Saved_model/model.ckpt") print(sess.run(result)) ```

leftrk

```python saver = tf.train.import_meta_graph("Saved_model/model.ckpt.meta") with tf.Session() as sess: saver.restore(sess, "Saved_model/model.ckpt") # 通过张量名称来获取张量 print(sess.run(tf.get_default_graph().get_tensor_by_name("add:0"))) ```

leftrk

**保存或加载部分变量** ```python saver = tf.train.Saver([v1]) with tf.Session() as sess: # 加载已经保存的模型,并通过已保存的模型中变量来计算加法 saver.restore(sess, "Saved_model/model.ckpt") print(sess.run(result)) ```

leftrk

**变量重命名** ```python # 注意定义时的name不一样!!! v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="other-v1") v2 = tf.Variable(tf.constant(1.0, shape=[1]), name="other-v2") # 将原来名称为v1的变量加载到现在变量v1中(名称为other-v1) # 将原来名称为v2的变量加载到现在变量v1中(名称为other-v2) saver = tf.train.Saver({"v1": v1, "v2": v2}) ```

leftrk

**滑动平均类的保存和加载** ```python # 通过变量重命名将原来变量v的滑动平均值直接赋值给v。 saver = tf.train.Saver({"v/ExponentialMovingAverage": v}) ``` ```python v = tf.Variable(0, dtype=tf.float32, name="v") ema = tf.train.ExponentialMovingAverage(0.99) # 通过variables_to_restore函数可以直接生成上面代码中提供的字典:{"v/ExponentialMovingAverage": v} print(ema.variables_to_restore()) # 输出:{'v/ExponentialMovingAverage': <tf.Variable 'v:0' shape=() dtype=float32_ref>} saver = tf.train.Saver(ema.variables_to_restore()) ```

leftrk

**常量方式保存(pb格式)** ```python # 导出当前计算图的GraphDef部分,只需要这一部分就可以完成从输入层到输出层的计算过程graph_def = tf.get_default_graph().as_graph_def() ``` ```python # 将圈中的变量及其取值转化为常量,同时将图中不必要的节点去掉。在5.4.2 节中将会看 # 到一些系统运算也会被转化为计算图中的节点(比如变量初始化操作)。如果只关心程序中定 # 义的某些计算时,和这些计算无关的节点就没有必要导出并保存了。在下面一行代码中,最 # 后一个参数['add']给出了需要保存的节点名称。add 节点是上面定义的两个变量相加的 # 操作。注意这里给出的是计算节点的名称,所以没有后面的:0 。 output_graph_def = graph_util.convert_variables_to_constants(sess, graph_def, ['add']) with tf.gfile.GFile("Saved_model/combined_model.pb", "wb") as f: f.write(output_graph_def.SerializeToString()) ```

leftrk

```python # 读取保存的模型文件,并将文件解析成对应的GraphDef Protocol Buffer with gfile.FastGFile(model_filename, 'rb') as f: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) # 将graph_def中保存的图加载到当前的图中。return_elements=["add:0"]给出了返回的张量 # 的名称。在保存的时候给出的是计算节点的名称,所以为"add",在加载的时候给出 # 的是张量的名称,所以为"add:0"。 result = tf.import_graph_def(graph_def, return_elements=["add:0"]) print(sess.run(result)) ```

leftrk

**tf.Coordinator主要用于协同多个线程一起停止**,并提供了`should_stop`、`request_ stop`和`join`三个函数。在启动线程之前,需要先声明一个tf.Coordinator类,并将这个类传入每一个创建的线程中。 **启动的线程需要一直查询tf.Coordinator类中提供的should_stop函数,当这个函数的返回值为True时,则当前线程也需要退出。每一个启动的线程都可以通过调用request_stop函数来通知其他线程退出。** 当某一个线程调用request_stop函数之后,should_stop函数的返回值将被设置为True这样其他的线程就可以同时终止了。

leftrk

**tf.QueueRunner主要用于启动多个线程来操作同一个队列**,启动的这些线程可以通过上面介绍的tf.Coordinator类来统一管理。

leftrk

```python # 先声明一个先进先出的队列,队列中最多100个元素,类型为实数型 queue = tf.FIFOQueue(100, "float") # 定义队列的入队操作 enqueue_op = queue.enqueue([tf.random_normal([1])]) # 使用tf.train.QueueRunner来创建多个线程运行队列的入队操作 # 第一个参数给出了被操作的队列; # 第二个参数表示需要启动5个线程,每个线程中运行的是enqueue_op操作 qr = tf.train.QueueRunner(queue, [enqueue_op] * 5) # 将定义过的QueueRunner加入TensorFlow计算图上指定的集合,默认tf.GraphKeys,QUEUE_RUNNERS tf.train.add_queue_runner(qr) # 定义出队操作 out_tensor = queue.dequeue() ```

leftrk

```python with tf.Session() as sess: # 使用tf.train.Coordinator来协同启动的线程 coord = tf.train.Coordinator() # 使用tf.train.QueueRunner时,需要明确调用tf.train.start_queue_runners来启动所有线程, # 否则因为没有线程运行入队操作,当调用出队操作时,程序会一直等待入队操作被运行。 # tf.train.start_queue_runners函数会默认启动tf.GraphKeys.QUEUE_RUNNERS集合中所有的QueueRunner, # 因为这个函数只支持启动指定集合中的QueueRnner,所以一般来说 # tf.train.add_queue_runner函数和tf.train.start_queue_runners函数会指定同一个集合。 threads = tf.train.start_queue_runners(sess=sess, coord=coord) # 获取队列中的值 for _ in range(3): print(sess.run(out_tensor)[0]) # 使用tf.train.Coordinator来停止所有线程 coord.request_stop() coord.join(threads) # 以上程序将启动5个线程来执行队列入队的操作,其中每一个线程都是将随机数写入队列。 # 于是在每次运行出队操作时,可以得到一个随机数 ```

leftrk

利用数据集读取数据有三个基本步骤: 1. **定义数据集的构造方法**,这个例子使用`tf.data.Dataset.from_tensor_slices()`,表明数据集是从一个张量中构建的,如果数据集是文件中构建的,则需要相应调整不同的构造方法。 2. **定义遍历器**,这个例子使用了简单的`one_shot_iterator`来遍历数据集,稍后将介绍更加灵活的`initializable_iterator`。 3. **使用`get_next`方法从遍历器中读取数据张量,作为计算图其他部分的输入。**

leftrk

**读取文本文件里的数据** ```python # 从文本文件创建数据集。假定每行文字是一个训练例子。这里可以提供多个文件。 input_files = ["./test1.txt", "./test2.txt"] dataset = tf.data.TextLineDataset(input_files) ```

leftrk

```python # 定义迭代器。 iterator = dataset.make_one_shot_iterator() # 这里get_next()返回一个字符串类型的张量,代表文件中的一行。 x = iterator.get_next() with tf.Session() as sess: for i in range(4): print(sess.run(x)) ```

leftrk

**解析TFRecord文件里的数据** 在图像相关任务中,输入数据通常以TFRecord形式存储,这时可以用`TFRecordDataset`来读取数据。与文本文件不同,每一个TFRecord都有自己不同的feature格式,因此在读取TFRecord时,需要提供一个`parser`函数来解析所读取的TFRecord的数据格式。

leftrk

**使用initializable_iterator来动态初始化数据集** ```python # 从TFRecord文件创建数据集,具体文件路径是一个placeholder,稍后再提供具体路径。 input_files = tf.placeholder(tf.string) dataset = tf.data.TFRecordDataset(input_files) dataset = dataset.map(parser) # 定义遍历dataset的initializable_iterator。 iterator = dataset.make_initializable_iterator() image, label = iterator.get_next() with tf.Session() as sess: # 首先初始化iterator,并给出input_files的值。 sess.run(iterator.initializer, feed_dict={input_files: ["output.tfrecords"]}) # 遍历所有数据一个epoch。当遍历结束时,程序会抛出OutOfRangeError。 while True: try: x, y = sess.run([image, label]) except tf.errors.OutOfRangeError: break ```

leftrk

**在上面的例子中,文件路径使用placeholder和feed_dict的方式传给数据集。使用这种方法,在实际项目中就不需要总是将参数写入计算图的定义,而可以使用程序参数的方式动态指定参数。** 另外注意到,上面例子中的循环体不是指定循环运行10次sess.run,而是使用*while(True) - try - except*的形式来将所有数据遍历一遍(即一个epoch)。这是因为在动态指定输入数据时,不同数据来源的数据量大小难以预知,而这个方法使我们不必提前知道数据量的精确大小。

leftrk

**数据集的高层操作** **1. dataset.map** `dataset = dataset.map(parser)` `dataset = dataset.map(lambda x:preprocess_for_train(x, image_size, image_size, None))` **2. dataset.batch & dataset.shuffle** - `dataset = dataset.batch(batch_size)`,**将数据组合成batch,参数batch_size代表要输出的每个batch由多少条数据组成。如果数据集中包含多个张量,那么batch操作将对每一个张量分开进行**。举例而言,如果数据集中的每一个数据(即iterator.get_next()的返回值)是image、label两个张量,其中image的维度是[300, 300],label的维度是[],batch_size是128,那么经过batch 操作后的数据集的每一个输出将包含两个维度分别是[128, 300, 300]和[128]的张量。 - `dataset = dataset.shuffle(buffer_size)`,随机打乱顺序,参数buffer_size等效于`tf.train.shuffle_batch`中的参数min_after_dequeue。shuffle算法在内部使用一个缓冲区中保存buffer_size条数据,每读入一条新数据时,从这个缓冲区中随机选择一条数据进行输出。缓冲区的大小越大,随机的性能越好,但占用的内存也越多。 **3. dataset.repeat** repeat是另一个常用的操作方法,它将数据集中的数据复制多份,其中每一份被称为一个epoch。 `dataset = dataset.repeat(N)` 上面代码将数据重复N份。需要指出的是,**如果数据集在repeat前己经进行了shuffle操作,输出的每个epoch中随机shuffle的结果并不会相同。**例如,如果输入数据是[1, 2, 3],shuffle后输出的第一个epoch是[2, 1, 3],而第二个epoch则有可能是[3, 2, 1]。repeat和map、shuffle、batch等操作一样,都只是计算图中的一个计算节点。repeat只代表重复相同的处理过程,并不会记录前一个epoch的处理结果。

leftrk

**4. 其他数据集操作** 除这些方法以外,数据集还提供了其他多种操作。例如: - concatenate()将两个数据集顺序连接起来; - take(N)从数据集中读取前N项数据; - skip(N)在数据集中跳过前N项数据; - flap_map()从多个数据集中轮流读取数据;

leftrk

```python # 1. 列举输入文件。训练和测试使用不同的数据 train_files = tf.train.match_filenames_once("output.tfrecords") test_files = tf.train.match_filenames_once("output_test.tfrecords") ```

leftrk

```python # 2. 解析一个TFRecord的方法。 def parser(record): features = tf.parse_single_example( record, features={ 'image_raw':tf.FixedLenFeature([],tf.string), 'pixels':tf.FixedLenFeature([],tf.int64), 'label':tf.FixedLenFeature([],tf.int64) }) decoded_images = tf.decode_raw(features['image_raw'],tf.uint8) retyped_images = tf.cast(decoded_images, tf.float32) images = tf.reshape(retyped_images, [784]) labels = tf.cast(features['label'],tf.int32) #pixels = tf.cast(features['pixels'],tf.int32) return images, labels ```

leftrk

```python # 3. 定义训练数据集 image_size = 299 # 定义神经网络输入层图片的大小。 batch_size = 100 # 定义组合数据batch的大小。 shuffle_buffer = 10000 # 定义随机打乱数据时buffer的大小。 # 定义读取训练数据的数据集。 dataset = tf.data.TFRecordDataset(train_files) dataset = dataset.map(parser) # 对数据集进行预处理,这里略去 # dataset = dataset.map(lambda image, label:( # preprocess_for_train(image, image_size, image_size, None), label) # 对数据进行shuffle和batching操作。这里省略了对图像做随机调整的预处理步骤。 dataset = dataset.shuffle(shuffle_buffer).batch(batch_size) # 重复NUM_EPOCHS个epoch。间接指定训练的轮数 NUM_EPOCHS = 10 dataset = dataset.repeat(NUM_EPOCHS) # 定义数据集迭代器。虽然定义数据集时没有直接使用placeholder来提供文件地址,但是 # tf.train.match_filenames_once方法得到的结果和与placeholder的机制类似,也需要 # 初始化,所以这里使用的是initializable_iterator。 iterator = dataset.make_initializable_iterator() image_batch, label_batch = iterator.get_next() ```

leftrk

```python # 4. 定义神经网络的结构个优化过程。这里与7.3.4小节相同。 def inference(input_tensor, weights1, biases1, weights2, biases2): layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1) return tf.matmul(layer1, weights2) + biases2 INPUT_NODE = 784 OUTPUT_NODE = 10 LAYER1_NODE = 500 REGULARAZTION_RATE = 0.0001 TRAINING_STEPS = 5000 weights1 = tf.Variable(tf.truncated_normal([INPUT_NODE, LAYER1_NODE], stddev=0.1)) biases1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE])) weights2 = tf.Variable(tf.truncated_normal([LAYER1_NODE, OUTPUT_NODE], stddev=0.1)) biases2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE])) y = inference(image_batch, weights1, biases1, weights2, biases2) # 计算交叉熵及其平均值 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=label_batch) cross_entropy_mean = tf.reduce_mean(cross_entropy) # 损失函数的计算 regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE) regularaztion = regularizer(weights1) + regularizer(weights2) loss = cross_entropy_mean + regularaztion # 优化损失函数 train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss) ```

leftrk

```python # 5. 定义测试用的数据集及相关 # 与训练时不同,测试数据的Dataset不需要经过随机翻转等预处理操作, # 也不需要打乱顺序和重复多个epoch,这里使用与训练数据相同的parser # 进行解析,调整分辨率到网络输入层大小,然后直接进行batching操作。 # 定义测试用的Dataset。 test_dataset = tf.data.TFRecordDataset(test_files) test_dataset = test_dataset.map(parser) test_dataset = test_dataset.batch(batch_size) # 定义测试数据上的迭代器。 test_iterator = test_dataset.make_initializable_iterator() test_image_batch, test_label_batch = test_iterator.get_next() # 定义测试数据上的预测结果为logits值最大的分类。 test_logit = inference(test_image_batch, weights1, biases1, weights2, biases2) predictions = tf.argmax(test_logit, axis=-1, output_type=tf.int32) ```

leftrk

```python # 6. 声明会话并运行神经网络的优化过程。 with tf.Session() as sess: # 初始化变量。 sess.run((tf.global_variables_initializer(), tf.local_variables_initializer())) # 初始化训练数据的迭代器。 sess.run(iterator.initializer) # 循环进行训练,直到数据集完成输入、抛出OutOfRangeError错误。 while True: try: sess.run(train_step) except tf.errors.OutOfRangeError: break # 初始化测试数据的迭代器。 sess.run(test_iterator.initializer) # 获取预测结果。 test_results = [] test_labels = [] while True: try: pred, label = sess.run([predictions, test_label_batch]) test_results.extend(pred) test_labels.extend(label) except tf.errors.OutOfRangeError: break # 计算准确率 correct = [float(y == y_) for (y, y_) in zip (test_results, test_labels)] accuracy = sum(correct) / len(correct) print("Test accuracy is:", accuracy) ```

leftrk

```python if i % 1000 == 0: # 配置运行时需要记录的信息 run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE) # 运行时记录运行信息的proto run_metadata = tf.RunMetadata() # 将配置信息和记录运行的proto传入运行的过程,从而记录运行时每一个节点的时间、内存信息 _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y_:ys}, options=run_options, run_metadata=run_metadata) # 将节点在运行时的信息写入日志文件 train_writer.add_run_metadata(run_metadata, 'step%03d'%i) print("After %d training step(s), loss on training batch is %g" % (step, loss_value)) ```

leftrk

```python # 1. 生成变量监控信息并定义生成监控信息日志的操作。 # 其中var给出了需要记录的张量,name给出了在可视化结果中显示的图发名称,这个名称一般与变量名一致。 def variable_summaries(var, name): # 将生成监控信息的操作放到统一命名空间下 with tf.name_scope('summaries'): # 通过tf.summary.histogram函数记录张量中元素的取值分布。对于给出的图表 # 名称和张量,tf.summary.histogram函数会生成一个Summary protocol buffer。 # 将Summary写入TensorBoard日志文件后,在HISTOGRAMS栏和DISTRIBUTION栏下 # 都会出现对应名称的图表。和TensorFlow中其他操作类似, # tf.summary.histogram函数不会立刻被执行,只有当sess.run函数明确调用这 # 个操作时,TensorFlow才会具正生成并输出Summary protocol buffer。 # 下文将更加详细地介绍如何理解HISTOGRAMS栏和DISTRIBUTION栏下的信息。 tf.summary.histogram(name, var) # 计算变量的平均值,并定义生成平均值信息日志的操作。记录变量平均值信息的日志标签名 # 为'mean/'+name,其中mean为命名空间,/是命名空间的分隔符,从图11.14中可以看到, # 在相同命名空间中的监控指标会被整合到同一栏中;name则给出了当前监控指标属于哪一个变量。 mean = tf.reduce_mean(var) tf.summary.scalar('mean/' + name, mean) # 计算变量的标准差,并定义生成其日志的操作 stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean))) tf.summary.scalar('stddev/' + name, stddev) ```

leftrk

```python # 2. 生成一层全链接的神经网络。 def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu): # 将同一层神经网络放在一个统一的命名空间下 with tf.name_scope(layer_name): # 声明神经网络边上的权重,并调用生成权重监控信息日志的函数。 with tf.name_scope('weights'): weights = tf.Variable(tf.truncated_normal([input_dim, output_dim], stddev=0.1)) variable_summaries(weights, layer_name + '/weights') # 声明神经网络的偏置项,并调用生成偏置项监控信息日志的函数。 with tf.name_scope('biases'): biases = tf.Variable(tf.constant(0.0, shape=[output_dim])) variable_summaries(biases, layer_name + '/biases') with tf.name_scope('Wx_plus_b'): preactivate = tf.matmul(input_tensor, weights) + biases # 记录神经网络输出节点在经过激活的数之前的分布。 tf.summary.histogram(layer_name + '/pre_activations', preactivate) activations = act(preactivate, name='activation') # 记录神经网络输出节点在经过激活函数之后的分布。在图11.17中,对于layer1,因 # 为使用了ReLU函数作为激活函数,所以所有小于0的值部被设为了0。于是在激活后 # 的layer1/activations图上所有的值都是大于0的。而对于layer2,因为没有使用 # 激活函数,所以layer2/activations和layer2/pre_activations一样。 tf.summary.histogram(layer_name + '/activations', activations) return activations ```

leftrk

```python # 3. 主函数 def main(): mnist = input_data.read_data_sets("../../datasets/MNIST_data", one_hot=True) # 定义输入 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') # 将输入向量还原成图片的像素矩阵,并通过tf.summary.image函数将当前的图片信息写入日志的操作 with tf.name_scope('input_reshape'): image_shaped_input = tf.reshape(x, [-1, 28, 28, 1]) tf.summary.image('input', image_shaped_input, 10) hidden1 = nn_layer(x, 784, 500, 'layer1') y = nn_layer(hidden1, 500, 10, 'layer2', act=tf.identity) # 计算交叉熵并定义生成交叉熵监控日志的操作 with tf.name_scope('cross_entropy'): cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=y, labels=y_)) tf.summary.scalar('cross_entropy', cross_entropy) with tf.name_scope('train'): train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy) # 当前模型在当前给定数据上的正确率,并定义生成正确率监控日志的操作。如果在sess.run # 时给定的数据训练batch,那么得到的正确率就是在这个训练batch上的正确率;如果给定的 # 数据为验证或者测试数据,那么得到的正确率就是在当前模型在验证或者测试数据上的正确率。 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) # 和TensorFlow其他操作类似,tf.summary.scalar、tf.summary.histogram和tf.summary.image # 函数都不会立即执行,需要通过sess.run来明确调用这些函数。因为程序中定义的写日志操作 # 比较多,一一调用非常麻烦,所以TensorFlow提供了tf.summary.merge_all函数来整理所有的 # 日志生成操作。在TensorFlow程序执行的过程中只要运行这个操作就可以将代码中定义的所有 # 日志生成操作执行一次,从而将所有日志文件。 merged = tf.summary.merge_all() with tf.Session() as sess: # 初始化写日志的writer,并将当前TensorFlow计算图写入日志。 summary_writer = tf.summary.FileWriter(SUMMARY_DIR, sess.graph) tf.global_variables_initializer().run() for i in range(TRAIN_STEPS): xs, ys = mnist.train.next_batch(BATCH_SIZE) # 运行训练步骤以及所有的日志生成操作,得到这次运行的日志。 summary, _ = sess.run([merged, train_step], feed_dict={x: xs, y_: ys}) # 将得到的所有日志写入日志文件,这样TensorBoard程序就可以拿到这次运行所对应的 # 运行信息。 summary_writer.add_summary(summary, i) summary_writer.close() ```

leftrk

```python # 生成可视化最终输出层向量所需要的日志文件。 def visualisation(final_result): # 使用一个新的变量来保存最终输出层向量的结果。因为embedding是通过TensorFlow # 中变量完成的,所以PROJECTOR可视化的都是TensorFlow中的变量。于是这里要 # 新定义一个变量来保存输出层向量的取值。 y = tf.Variable(final_result, name=TENSOR_NAME) summary_writer = tf.summary.FileWriter(LOG_DIR) # 通过projector.ProjectorConfig类来帮助生成日志文件。 config = projector.ProjectorConfig() # 增加一个需要可视化的embedding结果 embedding = config.embeddings.add() # 指定这个embedding结果对应的TensorFlow变量名称 embedding.tensor_name = y.name # 指定embedding结果所对应的原始数据信息。比如这里指定的就是每一张MNIST测试 # 图片对应的真实类别。在单词向量中可以是单词ID对应的单词。这个文件是可选的, # 如果没有指定那么向量就没有标签。 embedding.metadata_path = META_FIEL # 指定sprite图像。这个也是可选的,如果没有提供sprite图像,那么可视化的结果 # 每一个点就是一个小圆点,而不是具体的图片。 embedding.sprite.image_path = SPRITE_FILE # 在提供sprite图像时,通过single_image_dim可以指定单张图片的大小。 # 这将用于从sprite图像中截取正确的原始图片。 embedding.sprite.single_image_dim.extend([28,28]) # 将PROJECTOR所需要的内容写入日志文件。 projector.visualize_embeddings(summary_writer, config) # 生成会话,初始化新声明的变量并将需要的日志信息写入文件。 sess = tf.InteractiveSession() sess.run(tf.global_variables_initializer()) saver = tf.train.Saver() saver.save(sess, os.path.join(LOG_DIR, "model"), TRAINING_STEPS) summary_writer.close() ```