TensorFlow API
使用规范
tf.Variable: 用于 W 与 b 等参数
tf.constant: 用于超参数
tf.placeholder: 用于数据
tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
: 进行反向传播, 在优化的时候, 一定要
sess.run(optimizer, feed_dict={})
, run 的是 optimizer, 但是在测试查看损失或者准确率的时候, 要使用
sess.run(cost, feed_dict={})
, 不要进行优化
TensorFlow 中主要是要保存的数据都是需要先转为 String 类型的, 读取也是一样, 得到的数据要将其 ParseFromString, 遇到图像与 string 需要 decode; 在 TensorFlow 中 string 的语义应该为字节流
常用模块
tf.nn: TensorFlow 的核心模块
tf.train: 训练模块
tf.image: 图像增强模块
tf.image 模块
- tf.image.decode_jpeg
- tf.image.decode_png
- tf.image.encode_jpeg
- tf.image.encode_png
- tf.image.convert_image_dtype
: 在大部分的图像 API 中即使我们输入的 0-255 的图像, 它在内部还是会转换为 0-1 之间的实数, 接着在转为 0-255 返回给用户, 为了避免精度的损失, 推荐调用该函数提前转换类型
tf.image.resize_images
缩放算法:
0: 双线性插值法
1: 最近邻法
2: 双三次插值法
3: 面积插值法
tf.image.resize_image_with_crop_or_pad
: 对图像进行裁剪或者填充
tf.image.central_crop
: 等比例缩放, 比例在(0,1]
tf.image.flip_up_down
: 上下翻转
tf.image.flip_left_right
: 水平翻转
tf.image.transpose_image
: 沿着对角线翻转
- tf.image.adjust_brightness
- tf.image.adjust_constrast
- tf.image.adjust_hue
- tf.image.adjust_saturation
- tf.image.per_image_standardization
- tf.image.draw_bounding_boxes
: 画出 bounding_box
tf.expand_dims(image, 0)
: 将第 0 维度之前使用 1 添加一个维度, 该函数在添加维度的时候非常好用
运算
tf.clip_by_value(v, 1e-10, 1)
: 将 v 限定在 min 与 max
- tf.add
- tf.reduce_mean
- tf.reduce_sum
- tf.argmax
- tf.matmul
- tf.multiply
- tf.subtract
以上是 TensorFlow 中提供的运算节点的函数, 同时还提供了方便的操作符重载, 他们的区别仅仅是在生成的计算图时, 节点的名称略有不同, 对于 add 节点, 在函数中, 为 Add, 在操作符重载中, 为 add
随机数生成函数
tf.random_normal: 正态分布, 参数 stddev(standard deviation)为标准差
tf.truncated_normal: 与 tf.random_normal 类似, 正态分布, 如果生成的随机数偏移平均值超过 2 个标准差, 重新生成
tf.random_uniform: 均匀分布
tf.random_gamma: Gamma 分布
常量生成函数
- tf.zeros
- tf.ones
- tf.fill
- tf.constant
非线性激活函数
- tf.nn.sigmoid
- tf.nn.tanh
- tf.nn.relu
默认集合
定义在 tf.GraphKeys 中
tf.GraphKeys.TRAINABLE_VARIABLES
: 返回字符串 trainable_variables, 这是一个内置集合的名字; 默认通过 tf.Variable 定义时会添加到该集合中, 如果将 trainable=False 则不会了
tf.GraphKeys.LOSSES: 默认的损失集合名, 之后使用 tf.losses 模块才会使用到该内置集合
tf.GraphKeys.BIASES: 默认的偏移集合名
tf.GraphKeys.WEIGHTS
: 默认的权重集合名
BIASES 和 WEIGHTS 不常用
TRAINABLE_VARIABLES 包含在 MODEL_VARIABLES 中, MODEL_VARIABLES 包含在 GLOBAL_VARIABLES 中
tf.Optimizer 只优化
tf.GraphKeys.TRAINABLE_VARIABLES
中的变量
集合操作
tf.add_to_collection(name, value)
: 将 value 添加到名为 name 的集合中
tf.get_collection(name)
: 返回名为 name 的集合的所有元素
tf.get_collection(name, namespace_prefix)
: 返回名为 name 的集合 namespace_prefix 名称空间下的 Tensor, 注意末尾不能有 /
- CNN
- tf.nn.conv2d(input, filter, strides, padding)
- tf.nn.max_pool(input, ksize, strides, padding)
- tf.nn.bias_add(input, bias)
: 注意这里的 bias 应该为 (n, ) 之类的奇怪的矩阵, 也就是我们在创建 bias 的时候, 要
tf.get_variable('biases', [SIZE], init...)
, 而不能为
tf.get_variable('biases', [1, SIZE]或者[1, 1, 1, SIZE], init...)
TF-Slim 内置的神经网络模型
AlexNet, VGG, Inception, ResNet
- import tensorflow.contrib.slim as slim
- import tensorflow.contrib.slim.python.slim.nets.inception_v3 as inception_v3
: 定义了 InceptionV3 的网络结构, 但是在 Google 中已经完成了训练的权重不在这里, 需要从官网上下载过来进行迁移学习
简单的 fine-tune
加载模型(.ckpt 类型的, 不是. pb 类型)
找出我们需要的冻住的参数
找出我们需要重新训练的参数
创建一个 sess
加载冻住的参数
初始化需要重新训练的参数
优化损失函数
sess.run 进行训练
TFRecord 文件
写入. tfrecord 文件
- mnist = input_data.read_data_sets('mnist/', dtype=tf.uint8, one_hot=True)
- writer = tf.python_io.TFRecordWriter('demo.tfrecord')
- for i in range(mnist.train.num_examples):
- image_raw = mnist.train.images[i].tostring()
- example = tf.train.Example(features=tf.train.Features(feature={
- 'pixels': tf.train.Feature(int64_list=tf.train.Int64List(value=[len(mnist.train.images[i])])),
- 'label': tf.train.Feature(int64_list=tf.train.Int64List( value=[np.argmax(len(mnist.train.labels[i]))])),
- 'image_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_raw]))
- }))
- writer.write(example.SerializeToString())
读取文件
- reader = tf.TFRecordReader()
- # 加载文件名队列
- filename_queue = tf.train.string_input_producer(['./demo.tfrecord'])
- _, serialized_example = reader.read(filename_queue)
- features = tf.parse_single_example(serialized_example, features={
- 'pixels': tf.FixedLenFeature([], tf.int64),
- 'label': tf.FixedLenFeature([], tf.int64),
- 'image_raw': tf.FixedLenFeature([], tf.string)
- })
- image = tf.decode_raw(features['image_raw'], tf.uint8)
- pixels = tf.cast(features['pixels'], tf.int32)
- label = tf.cast(features['label'], tf.int32)
- with tf.Session() as sess:
- coord = tf.train.Coordinator()
- # 这个必须有, 否则程序一直阻塞
- threads = tf.train.start_queue_runners(sess=sess, coord=coord)
- for i in range(10):
- print(sess.run([image, pixels, label]))
神经网络优化
- tf.train.exponential_decay(staircase=True)
- :
如果 staircase 为 True 则学习率的衰减为阶梯型的
参照公式:
decay_learning_rate=learning_rate*decay_rate^(global_step/decay_step)
其中, learning_rate 为初始学习率(如 0.1), decay_rate 为衰减系数(0-1, 如 0.1), decay_step 为衰减速率(如 50)
内置损失函数
- tf.nn.softmax_cross_entropy_with_logits(labels=,logits=)
- tf.nn.sigmoid_cross_entropy_with_logits(labels=,logits=)
- tf.nn.sparse_softmax_cross_entropy_with_logits(labels=,logits=)
自定义损失函数
tf.greater(v1, v2): v1> v2 返回 True, 否则返回 False
tf.where(tf.greater(v1, v2), v1, v2)
: 分段函数, 当 v1>v2 是为 v1, 否则为 v2
模型持久化(.ckpt)
保存模型
- ```
- saver = tf.train.Saver()
- with tf.Session() as sess:
- sess.run(tf.global_variables_initializer())
- saver.save(sess, '/path/to/model.ckpt') # .ckpt 为 CheckpointState
- # TensofFlow 会将模型分成图结构与变量数据分别保存, 其中. meta 为图结构, 为 MetaGraphDef
- ``
* 生成三个文件:
.meta,.data,checkpoint, 注意没有 model.ckpt` 文件
导入模型
只导入变量数据, 而不导入图的结构, 这样我们使用模型的时候, 需要先创建好图的结构, 在使用 saver 导入变量, 这样我们需要时初始化全局变量, 因为变量的是从外部导入过来的
- ```py
- saver = tf.train.Saver()
- with tf.Session() as sess:
- saver.restore(sess, '/path/to/model.ckpt')
- ```
导入图并导入数据
py saver = tf.train.import_meta_graph('/path/to/model.ckpt.meta') with tf.Session() as sess: sess.restore(sess, '/path/to/model.ckpt') # 通过张量的名称来获取张量, 因为在导入图时, 我们一般处于一个新的项目中, 没有图, 而导入了图我们有没有引用, 这个时候时候就使用如下方法即可 print(sess.run(tf.get_default_graph().get_tensor_\ by_name('add:0'))
保存为. ckpt 格式, 计算图与变量是分开的, 但是有时候, 尤其是在保存预训练模型的模型的时候, 我们希望 freeze 一些层, 也就是将一些 W 和 b 的变量固定住, 这个时候就需要将 Variable 转为 constant, 见下面
模型持久化(.pb)
保存模型
py from tensorflow.python.framework import graph_util with tf.Session() as sess: sess.run(init_op) with tf.gile.GFile('/path/to/model.pb', 'wb') as fd: graph_def = tf.get_default_graph().as_graph_def() ouput_graph_def = graph_util.convert_variables_to_constants(sess, graph_def, ['add']) fd.write(output_graph_def.SerializeToString())
导入模型
py with tf.Session() as sess: with tf.gile.GFile('/path/to/model.pb', 'rb') as fd: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) result = tf.import_graph_def(graph_def, return_elements=['add:0']) # 注意这里填写的是张量名, add 为节点名, 因为我们在上面将变量转为了常量, 所以可以直接输出结果, 现在 result 保存了结果 print(sess.run(result))
ckpt(CheckPointState)对象
tf.get_checkpoint_state(dirpath)
: 返回 ckpt 对象
ckpt.model_checkpoint_path
: ckpt 文件路径
- Variables
- tf.global_variables()
: 返回所有的 Variable, 他们存储在
tf.GraphKeys.VARIABLES
tf.Variable: 创建一个变量
tf.get_variable: 创建一个变量, 与 tf.Variable 不同的是一定要指定变量名
在命名空间中创建变量, reuse 一定要记得到使用上
- ```py
- # 如果之前没有 foo 命名空间则创建一个新的命名空间, 如果 reuse 为 True 则该在当前开启
- # 的上下文管理器中不能创建新的变量, 如果 reuse=False, 可以创建新的变量, 但是
- # 无法创建已经存在的变量, 变量名的全名为 "foo/name:0", 其中 0 表示节点的第 0 个输出
- with tf.variable_scope('foo', reuse=False):
- v = tf.get_variable('v', shape=[1, 1], initializer=tf.constants_initializer())
- ```
创建名为空的名称空间(相当于顶级)
with tf.variable_scope('', result=True): # 可以拿到在上面 foo 创建的 v v = tf.get_variable('foo/v', shape=[1, 1]) print(v)
命名空间的应用
当神经网络越来越深的时候, W 与 b 等权重与参数会越来越多, 越来越难管理, 所以我们以一层为单位, 创建一个命名空间, 管理里面的变量, 这样在函数传递参数的时候我们也不需要传递这么多的参数, 只要通过名称空间获取即可
常用 API
tf.group([train, cost])
: 在 sess.run([...])是我们传入一个列表是为了可以同时计算多个 op, 我们也可以通过
op = tf.group([...])
的方法返回一个 op, 这样在 sess.run(op)就可以写少一点了
tf.one_hot(labels, C, axis=0)
: 将 labels 转为维度为 C, 在 axis=0 方向的填充的 one_hot
tf.reduce_mean(mat, axis=0)
: 计算均值
TensorFlow 文件读取
tf.train.string_input_producer(filename_list, shuffle=False, num_epochs=5)
: 将 filename_list 中的文件预先记录加来, 将来要放到文件名队列中, 返回文件名队列
tf.WholeFileReader()
: 返回 reader 对象, 用于读取文件名队列加载文件
tf.FixLengthRecordReader(record_bytes=bytes)
: 返回 reader 对象, 每次读取定长 record_bytes
tf.train.start_queue_runner(sess=sess)
: 与上面的
- string_input_producer
- , WholeFileReader,
- FixLengthRecordReader
关系密切, 调用此方法才真正的将文件名队列加载到队列中, tf 读取数据才起步
tf.examples.tutorials.mnist.input_data.read_data_sets('MNIST_data', one_hot=True)
: input_data 模块调用 read_data_sets 函数读取注明的 MNIST 数据到 MNIST_data 中, 如果不存在则从网上下载, 返回一个 Datasets 对象
Datasets 的属性: train.images, train.labels, validation.images, validation.labels, test.images, test.labels, 他们都是 np.ndarray; next_batch(50): 下一个 batch(采用 mini-batch)
tf.gfile: 类似于 os 模块, 可以等价替换掉 os 模块
tf.truncated_normal(shape, stddev=0.1)
: 一般用于 W 的初始化
tf.zeros(shape_tuple)
: 类似于 np.zeros
运算
tf.matmul, tf.reshape, tf.add, tf.equal
队列
- tf.FIFOQueue
- tf.RandomShuffleQueue
: 每次出队会随机从队列中取出一个元素
tf.train.Coordinator
: 多线程协同
tf.train.QueueRunner
: 启动多线程操作同一个队列
配合 tf.train.Cooridator 和
tf.train.QueueRunner
图像增强 API
tf.random_crop(img, [h, w, c])
: 裁剪图片
tf.image.random_brightness(img, max_delta=60)
: 亮度
tf.image.random_contrast(img, lower=0.2, upper=1.8)
: 对比度
tf.image.random_flip_left_right(img)
: 随机翻转, 50% 水平左右翻转, 50% 不会
绘制标注框
方式一
- with tf.Session() as sess:
- image = tf.image.convert_image_dtype(tf.image.decode_jpeg(tf.gfile.FastGFile('/path/to/pic.jpeg', 'rb').read()), tf.float32)
- # 要为 4 维度的, 第一个维度为样本的个数
- batched = tf.expand_dims(image, 0)
- # 一定要为 3 维度的
- boxes = tf.constant([[[0.5, 0.5, 0.75, 0.75]]])
- image_with_box = tf.image.draw_bounding_boxes(batched, boxes)
- result = sess.run(image_with_box)
- plt.imshow(result)
- plt.show()
方式二
- with tf.Session() as sess:
- image = tf.image.convert_image_dtype(tf.image.decode_jpeg(tf.gfile.FastGFile('/path/to/pic.jpeg', 'rb').read()), tf.float32)
- # 要为 4 维度的, 第一个维度为样本的个数
- batched = tf.expand_dims(image, 0)
- # 一定要为 3 维度的
- boxes = tf.constant([[[0.5, 0.5, 0.75, 0.75]]])
- # 注意注意注意:!!!, 此处一定要给出 min_object_coverted=0.1 参数
- bbox_begin, bbox_size, bbox_for_draw = tf.image.sample_distorted_bounding_boxes(tf.shape(image), bounding_boxes=bboxes, min_object_coverted=0.1)
- image_with_box = tf.image.draw_bounding_boxes(image, bbox_for_draw)
- result = sess.run(image_with_box)
- plt.imshow(result)
- plt.show()
图像预处理最佳实践
使用到的函数
- tf.image.sample_distorted_bounding_box(tf.shape(image), bounding_boxes=bbox, min_object_covered=0.1)
- tf.image.convert_image_dtype
- tf.image.resize_images
- tf.image.random_flip_left_right
tf.slice: 从原始图片中裁剪标注框大小
代码
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- import tensorflow as tf
- import numpy as np
- import matplotlib.pyplot as plt
- # 对输入的图像进行饱和度, 对比度, 亮度, 色相的随机变化
- def distort_color(image, color_ordering=0):
- if color_ordering == 0:
- image = tf.image.random_brightness(image, max_delta=32./255.)
- image = tf.image.random_saturation(image, lower=0.5, upper=1.5)
- image = tf.image.random_hue(image, max_delta=0.2)
- image = tf.image.random_contrast(image, lower=0.5, upper=1.5)
- elif color_ordering == 1:
- image = tf.image.random_saturation(image, lower=0.5, upper=1.5)
- image = tf.image.random_brightness(image, max_delta=32./255.)
- image = tf.image.random_hue(image, max_delta=0.2)
- image = tf.image.random_contrast(image, lower=0.5, upper=1.5)
- return tf.clip_by_value(image, 0.0, 1.0)
- # 从原始图像中裁剪出一个 bounding box, 对 bounding box 的图像进行缩放到可以输入到 NN 中的大小
- def preprocess_for_train(image, height, width, bbox):
- if bbox is None:
- bbox = tf.contrast([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4])
- if image.dtype != tf.float32:
- image = tf.image.convert_image_dtype(image, dtype=tf.float32)
- bbox_begin, bbox_size, _ = tf.image.sample_distorted_bounding_box(tf.shape(image), bounding_boxes=bbox, min_object_covered=0.1)
- distorted_image = tf.slice(image, bbox_begin, bbox_size)
- distorted_image = tf.image.resize_images(distorted_image, [height, width], method=np.random.randint(4))
- distorted_image = tf.image.random_flip_left_right(distorted_image)
- distorted_image = distort_color(distorted_image, np.random.randint(1))
- return distorted_image
- def main():
- with tf.Session() as sess:
- sess.run(tf.global_variables_initializer())
- image_raw_data = tf.gfile.FastGFile('./15.jpg', 'rb').read()
- img_data = tf.image.decode_jpeg(image_raw_data)
- boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]])
- for i in range(6):
- result = preprocess_for_train(img_data, 299, 299, boxes)
- plt.imshow(sess.run(result))
- plt.show()
- if __name__ == '__main__':
- main()
- TensorBoard
- tensorboard --logdir dir/ --port 6006
: 启动 tensorboard
MNIST 识别
BP 神经网络最佳实践
mnist_inference.py: 提供前向传播
- import os
- import sys
- import time
- import tensorflow as tf
- from tensorflow.python.framework import graph_util
- from tensorflow.examples.tutorials.mnist import input_data
- INPUT_NODES = 784
- OUTPUT_NODES = 10
- LAYER1_NODES = 50
- BATCH_SIZE = 100
- LEARNING_RATE = 0.001
- REGULARIZATION_RATE = 0.0001
- TRAINING_STEP = 30000
- def get_weight_variable(shape, regularize):
- weights = tf.get_variable('weights', shape=shape, initializer=tf.truncated_normal_initializer(stddev=0.1, seed=1))
- if regularize:
- tf.add_to_collection('losses', regularize(weights))
- return weights
- def inference(input_tensor, regularize):
- with tf.variable_scope('layer1', reuse=False):
- weights = get_weight_variable([INPUT_NODES, LAYER1_NODES], regularize)
- biases = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODES]), name='biases')
- layer1 = tf.nn.relu(tf.matmul(input_tensor, weights) + biases)
- with tf.variable_scope('layer2', reuse=False):
- weights = get_weight_variable([LAYER1_NODES, OUTPUT_NODES], regularize)
- biases = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODES]), name='biases')
- layer2 = tf.matmul(layer1, weights) + biases
- return layer2
mnist_train.py: 训练网络, 保存模型
- import os
- import sys
- import time
- import tensorflow as tf
- from tensorflow.python.framework import graph_util
- from tensorflow.examples.tutorials.mnist import input_data
- import mnist_inference
- def train(mnist):
- X = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODES], name='X')
- Y = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODES], name='Y')
- global_step = tf.Variable(0, trainable=False)
- regularize = tf.contrib.layers.l2_regularizer(0.001)
- Z2 = mnist_inference.inference(X, regularize)
- cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=Z2)) + tf.add_n(tf.get_collection('losses'))
- optimizer = tf.train.AdamOptimizer(mnist_inference.LEARNING_RATE).minimize(cost, global_step=global_step)
- prediction = tf.equal(tf.argmax(Y, 1), tf.argmax(Z2, 1))
- accuracy = tf.reduce_mean(tf.cast(prediction, tf.float32))
- init_op = tf.global_variables_initializer()
- saver = tf.train.Saver()
- with tf.Session() as sess:
- sess.run(init_op)
- for i in range(30000):
- batch = mnist.train.next_batch(mnist_inference.BATCH_SIZE)
- _, accuracy_score, step = sess.run([optimizer, accuracy, global_step], feed_dict={X:batch[0], Y:batch[1]})
- if i % 1000 == 0:
- print('After %s step(s), accuracy is %g' % (step, accuracy_score))
- saver.save(sess, 'models/model.ckpt', global_step=global_step) # 使用 global_step=global_step, 则持久化的 ckpt 文件名会加上 - global_step 的名字
- def main(argv=None):
- mnist = input_data.read_data_sets('mnist/', one_hot=True)
- train(mnist)
- if __name__ == '__main__':
- tf.App.run()
mnist_eval.py: 加载模型, 测试训练的网络
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- import os
- import sys
- import time
- import numpy as np
- import tensorflow as tf
- from tensorflow.python.framework import graph_util
- from tensorflow.examples.tutorials.mnist import input_data
- import mnist_inference
- import mnist_train
- def eval(mnist):
- X = tf.placeholder(tf.float32, shape=[None, mnist_inference.INPUT_NODES], name='X')
- Y = tf.placeholder(tf.float32, shape=[None, mnist_inference.OUTPUT_NODES], name='Y')
- Z2 = mnist_inference.inference(X, None)
- prediction = tf.equal(tf.argmax(Y, 1), tf.argmax(Z2, 1))
- accuracy = tf.reduce_mean(tf.cast(prediction, tf.float32))
- validate_feed = {X:mnist.validation.images, Y:mnist.validation.labels}
- saver = tf.train.Saver()
- while True:
- with tf.Session() as sess:
- ckpt = tf.train.get_checkpoint_state('models/')
- if ckpt and ckpt.model_checkpoint_path:
- saver.restore(sess, ckpt.model_checkpoint_path)
- 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), validation accuracy = %g' % (global_step, accuracy_score))
- else:
- print('Checkpoint File Is Not Found')
- time.sleep(10)
- def main(argv=None):
- mnist = input_data.read_data_sets('mnist/', one_hot=True)
- eval(mnist)
- if __name__ == '__main__':
- tf.App.run()
LeNet 实现手写数字识别
Conv->ReLU --> Conv->ReLU --> FC->FC
CNN 中使用范式
Filter 的大小一般不会超过 5x5, 一般在 1x1, 3x3, 5x5, 但是也有些模型有 7x7 和 11x11; Filter 的 stride 一般为[1, 1, 1, 1]; Filter 的个数一般从 32 开始, 接着逐渐翻倍
MaxPool 的大小一般为 [1, 2, 2, 1] 和[1, 3, 3, 1], strides 一般为 [1, 2, 2, 1] 和[1, 3, 3, 1], 这样做保证了每次都是将图像的宽与高缩小到原来的一半
Conv 层连续最多 3 层, VGG 就是这样的; Pool 则一般可有可无, 但是大部分的网络模型都有
在原始的输入图像矩阵中, 维度为
[batch_size, h, w, c]
, 但是我们的 filter 为
[h, w, c, num_of_fitlers]
从 pool 得到的矩阵, 它的维度为[size, h, w, c], 因此如果接下来为 FC, 则我们需要他变为[node, h * w * c]
指定设备运行
在 TensorFlow 中 CPU 的设备名都为 / CPU:0
使用
with tf.device('/gpu:0'):
的语法, 在上下面管理器中定义 OpNode 和变量, 但是在 Tensorflow 不同版本中 GPU 处理的数据类型不同, 有些版本无法处理 float64 类型的, 如果人为强制的指定则会报错, 不能把代码写死, 所以这里在 sess.run 时要指定一个关键字参数,
sess.run(optimizer, allow_soft_placement=True)
, 这样当 GPU 无法处理时自动使用 CPU 处理
一般将计算密集型放到 GPU 上处理, 其他操作放在 CPU 上, 一般将神经网络运算放到 GPU 上, 将神经网络的优化跑在不同的 GPU 上, 将简单的运算, 如 precition 放到 CPU 上运算
来源: http://www.bubuko.com/infodetail-3012948.html