-TensorFlow:实战Google深度学习框架
        -推荐序1
        -推荐序2
        -推荐序3
        -前言
        -目录
        -第1章 深度学习简介
            -1.1 人工智能、机器学习与深度学习 (1)
            -1.2 深度学习的发展历程
            -1.3 深度学习的应用
                -1.3.1 计算机视觉
                -1.3.2 语音识别
                -1.3.3 自然语言处理
                -1.3.4 人机博弈
            -1.4 深度学习工具介绍和对比
            -小结
        -第2章 TensorFlow环境搭建
            -2.1 TensorFlow的主要依赖包
                -2.1.1 Protocol Buffer
    -      name:张三
    -      id:12345
    -      email: zhangsan@abc.com
    -书名页
    -       张三
    -       12345
    -       zhangsan@abc.com
    -书名页
    -   {
    -       "name": "张三",
    -       "id": "12345",
    -       "email": “zhangsan@abc.com”,
    -   }
    -   message user{
    -     optional string name = 1;
    -     required int32 id = 2;
    -     repeated string email = 3;
    -   }
                -2.1.2 Bazel
    -   -rw-rw-r--  root root 208    BUILD
    -   -rw-rw-r--  root root 48     hello_lib.py
    -   -rw-rw-r--  root root 47     hello_main.py
    -   -rw-rw-r--  root root 0      WORKSPACE
    -   def print_hello_world():
    -       print("Hello World")
    -   import hello_lib
    -   hello_lib.print_hello_world()
    -   py_library(
    -       name = "hello_lib",
    -       srcs = [
    -           "hello_lib.py",
    -       ]
    -   )
    -   py_binary(
    -       name = "hello_main",
    -       srcs = [
    -           "hello_main.py",
    -       ],
    -       deps = [
    -           ":hello_lib",
    -       ],
    -   )
            -2.2 TensorFlow安装
                -2.2.1 使用Docker安装
    -   $ docker run -it -p 8888:8888 –p 6006:6006\
    -   cargo.caicloud.io/tensorflow/ tensorflow:0.12.0
    -   $ nvidia-docker run -it -p 8888:8888 –p 6006:6006 \
    -              cargo.caicloud.io/tensorflow/tensorflow:0.12.0-gpu
                -2.2.2 使用pip安装
    -   # 在Ubuntu/Linux 64-bit环境下安装。
    -   $ sudo apt-get install python-pip python-dev
    -   # 在Mac OS X环境下安装。
    -   $ sudo easy_install pip
    -   $ sudo easy_install --upgrade six
    -   # Ubuntu/Linux 64-bit, Python 2.7环境。
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/ cpu/tensorflow-0.9.0-cp27-none-linux_x86_64.whl
    -   # Ubuntu/Linux 64-bit, Python 3.4环境。
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/ cpu/tensorflow-0.9.0-cp34-cp34m-linux_x86_64.whl
    -   # Ubuntu/Linux 64-bit, CPU only, Python 3.5环境。
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/ cpu/tensorflow-0.9.0-cp35-cp35m-linux_x86_64.whl
    -   # Mac OS X, Python 2.7环境。
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/ tensorflow-0.9.0-py2-none-any.whl
    -   # Mac OS X, Python 3.4 or 3.5环境。
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/ tensorflow-0.9.0-py3-none-any.whl
    -   # Python 2.7 环境
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/ gpu/tensorflow-0.9.0-cp27-none-linux_x86_64.whl
    -   # Python 3.4环境
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/ gpu/tensorflow-0.9.0-cp34-cp34m-linux_x86_64.whl
    -   # Python 3.5环境
    -   $ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/ gpu/tensorflow-0.9.0-cp35-cp35m-linux_x86_64.whl
    -   # Python 2环境
    -   $ sudo pip install --upgrade $TF_BINARY_URL
    -   # Python 3环境
    -   $ sudo pip3 install --upgrade $TF_BINARY_URL
                -2.2.3 从源代码编译安装
    -   $ sudo apt-get install software-properties-common
    -   $ sudo add-apt-repository ppa:webupd8team/java
    -   $ sudo apt-get update
    -   $ sudo apt-get install oracle-java8-installer
    -   $ sudo apt-get install pkg-config zip g++ zlib1g-dev unzip
    -   $ chmod +x bazel-0.3.1-jdk7-installer-linux-x86_64.sh
    -   $ ./bazel-0.3.1-jdk7-installer-linux-x86_64.sh –user [(19)](part0009_split_004.html#VF-6c6a83a4f5d442b18ece5cfab416f8bb)
    -   $ export PATH="$PATH:$HOME/bin"
    -   # Python 2.7环境
    -   $ sudo apt-get install python-numpy swig python-dev python-wheel
    -   # Python 3.x环境
    -   $ sudo apt-get install python3-numpy swig python3-dev python3-wheel
    -   tar xvzf cudnn-7.5-linux-x64-v4.tgz
    -   sudo cp cudnn-7.5-linux-x64-v4/cudnn.h /usr/local/cuda/include
    -   sudo cp cudnn-7.5-linux-x64-v4/libcudnn* /usr/local/cuda/lib64
    -   sudo chmod a+r /usr/local/cuda/include/cudnn.h \
    -                 /usr/local/cuda/lib64/ libcudnn*
    -   /usr/bin/ruby -e "$(curl -fsSL \
    -       https://raw.githubusercontent.com/Homebrew/install/master/install)"
    -   $ brew install bazel swig
    -   $ sudo easy_install -U six
    -   $ sudo easy_install -U numpy
    -   $ sudo easy_install wheel
    -   $ sudo easy_install ipython
    -   $ brew install coreutils
    -   $ brew tap caskroom/cask
    -   $ brew cask install cuda
    -   export CUDA_HOME=/usr/local/cuda
    -   export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$CUDA_HOME/lib"
    -   export PATH="$CUDA_HOME/bin:$PATH"
    -   $ sudo mv include/cudnn.h /Developer/NVIDIA/CUDA-7.5/include/
    -   $ sudo mv lib/libcudnn* /Developer/NVIDIA/CUDA-7.5/lib
    -   $ sudo ln -s /Developer/NVIDIA/CUDA-7.5/lib/libcudnn* /usr/local/cuda/lib/
    -   $ git clone https://github.com/tensorflow/tensorflow
    -   $ cd tensorflow
    -   $ ./configure
    -   # 配置Python的路径。
    -   Please specify the location of python. [Default is /usr/bin/python]:
    -   # 配置是否支持谷歌云平台。
    -   Do you wish to build TensorFlow with Google Cloud Platform support? [y/N]N
    -   No Google Cloud Platform support will be enabled for TensorFlow
    -   # 配置是否支持GPU。
    -   Do you wish to build TensorFlow with GPU support? [y/N] y
    -   GPU support will be enabled for TensorFlow
    -   # 配置GPU。
    -   Please specify which gcc nvcc should use as the host compiler. [Default is /usr/bin/gcc]:
    -   # 配置Cuda SDK版本。
    -   Please specify the Cuda SDK version you want to use, e.g. 7.0\. [Leave empty to use system default]: 7.5
    -   # 配置CUDA toolkit目录。
    -   Please specify the location where CUDA 7.5 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:
    -   # 配置Cudnn版本。
    -   Please specify the Cudnn version you want to use. [Leave empty to use system default]: 4
    -   # 配置cuDNN目录。
    -   Please specify the location where cuDNN 4 library is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:
    -   # 配置GPU计算能力。
    -   Please specify a list of comma-separated Cuda compute capabilities you want to build with.
    -   You can find the compute capability of your device at: https://developer. nvidia.com/cuda-gpus.
    -   Please note that each additional compute capability significantly increases your build time and binary size.
    -   Setting up Cuda include
    -   Setting up Cuda lib
    -   Setting up Cuda bin
    -   Setting up Cuda nvvm
    -   Setting up CUPTI include
    -   Setting up CUPTI lib64
    -   Configuration finished
    -   $ bazel build -c opt --config=cuda \
    -             //tensorflow/tools/pip_package:build_ pip_package
    -   $ bazel-bin/tensorflow/tools/pip_package/build_pip_package \
    -              /tmp/tensorflow_ pkg
    -   $ sudo pip install /tmp/tensorflow_pkg/tensorflow-0.9.0-py2-none-any.whl
            -2.3 TensorFlow测试样例
            -小结
        -第3章 TensorFlow入门
            -3.1 TensorFlow计算模型——计算图
                -3.1.1 计算图的概念
                -3.1.2 计算图的使用
    -   import tensorflow as tf
    -   a = tf.constant([1.0, 2.0], name="a")
    -   b = tf.constant([2.0, 3.0], name="b")
    -   result = a + b
    -   # 通过a.graph可以查看张量所属的计算图。因为没有特意指定,所以这个计算图应该等于 当前默认的计算图。所以下面这个操作输出值为True。
    -   print(a.graph is tf.get_default_graph())
    -   import tensorflow as tf
    -   g1 = tf.Graph()
    -   with g1.as_default():
    -       # 在计算图g1中定义变量“v”,并设置初始值为0。
    -       v = tf.get_variable(
    -           "v", initializer=tf.zeros_initializer(shape=[1]))
    -   g2 = tf.Graph()
    -   with g2.as_default():
    -       # 在计算图g2中定义变量“v”,并设置初始值为1。
    -       v = tf.get_variable(
    -           "v", initializer=tf.ones_initializer(shape=[1]))
    -   # 在计算图g1中读取变量“v”的取值。
    -   with tf.Session(graph=g1) as sess:
    -       tf.initialize_all_variables().run()
    -       with tf.variable_scope("", reuse=True):
    -           # 在计算图g1中,变量“v”的取值应该为0,所以下面这行会输出[0.]。
    -           print(sess.run(tf.get_variable("v")))
    -   # 在计算图g2中读取变量“v”的取值。
    -   with tf.Session(graph=g2) as sess:
    -       tf.initialize_all_variables().run()
    -       with tf.variable_scope("", reuse=True):
    -           # 在计算图g2中,变量“v”的取值应该为1,所以下面这行会输出[1.]。
    -           print(sess.run(tf.get_variable("v")))
    -   g = tf.Graph()
    -   # 指定计算运行的设备。
    -   with g.device('/gpu:0'):
    -       result = a + b
            -3.2 TensorFlow数据模型——张量
                -3.2.1 张量的概念
    -   import tensorflow as tf
    -   # tf.constant是一个计算,这个计算的结果为一个张量,保存在变量a中。
    -   a = tf.constant([1.0, 2.0], name="a")
    -   b = tf.constant([2.0, 3.0], name="b")
    -   result = tf.add(a, b, name="add")
    -   print result
    -   '''
    -   输出:
    -   Tensor("add:0", shape=(2,), dtype=float32)
    -   '''
    -   import tensorflow as tf
    -   a = tf.constant([1, 2], name="a")
    -   b = tf.constant([2.0, 3.0], name="b")
    -   result = a + b
    -   ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("b:0", shape=(2,), dtype=float32)'
                -3.2.2 张量的使用
    -   # 使用张量记录中间结果
    -   a = tf.constant([1.0, 2.0], name="a")
    -   b = tf.constant([2.0, 3.0], name="b")
    -   result = a + b
    -   # 直接计算向量的和,这样可读性会比较差。
    -   result = tf.constant([1.0, 2.0], name="a") +
    -              tf.constant([2.0, 3.0], name="b")
            -3.3 TensorFlow运行模型——会话
    -   # 创建一个会话。
    -   sess = tf.Session()
    -   # 使用这个创建好的会话来得到关心的运算的结果。比如可以调用sess.run(result), 来得到3.1节样例中张量result的取值。
    -   sess.run(...)
    -   # 关闭会话使得本次运行中使用到的资源可以被释放。
    -   sess.close()
    -   # 创建一个会话,并通过Python中的上下文管理器来管理这个会话。
    -   with tf.Session() as sess:
    -       # 使用这创建好的会话来计算关心的结果。
    -       sess.run(...)
    -   # 不需要再调用“Session.close()”函数来关闭会话,  当上下文退出时会话关闭和资源释放也自动完成了。
    -   sess = tf.Session()
    -   with sess.as_default():
    -       print(result.eval())
    -   sess = tf.Session()
    -   # 下面的两个命令有相同的功能。
    -   print(sess.run(result))
    -   print(result.eval(session=sess))
    -   sess = tf. InteractiveSession ()
    -   print(result.eval())
    -   sess.close()
    -   config = tf.ConfigProto(allow_soft_placement=True,
    -                                log_device_placement=True)
    -   sess1 = tf. InteractiveSession(config=config)
    -   sess2 = tf. Session(config=config)
            -3.4 TensorFlow实现神经网络
                -3.4.1 TensorFlow游乐场及神经网络简介
                -3.4.2 前向传播算法简介
    -   a = tf.matmul(x, w1)
    -   y = tf.matmul(a, w2)
                -3.4.3 神经网络参数与TensorFlow变量
    -   weights = tf.Variable(tf.random_normal([2, 3], stddev=2))
    -   biases = tf.Variable(tf.zeros([3]))
    -   w2 = tf.Variable(weights.initialized_value())
    -   w3 = tf.Variable(weights.initialized_value() * 2.0)
    -   import tensorflow as tf
    -   # 声明w1、w2两个变量。这里还通过seed参数设定了随机种子,  这样可以保证每次运行得到的结果是一样的。
    -   w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1))
    -   w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))
    -   # 暂时将输入的特征向量定义为一个常量。注意这里x是一个1*2的矩阵。
    -   x = tf.constant([[0.7, 0.9]])
    -   # 通过3.4.2小节描述的前向传播算法获得神经网络的输出。
    -   a = tf.matmul(x, w1)
    -   y = tf.matmul(a, w2)
    -   sess = tf.Session()
    -   # 与3.4.2中的计算不同,这里不能直接通过sess.run(y)来获取y的取值,  因为w1和w2都还没有运行初始化过程。下面的两行分别初始化了w1和w2两个变量。
    -   sess.run(w1.initializer)  # 初始化w1
    -   sess.run(w2.initializer)  # 初始化w2 输出[[3.95757794]]
    -   print(sess.run(y))
    -   sess.close()
    -   init_op = tf.initialize_all_variables()
    -   sess.run(init_op)
    -   w1 = tf.Variable(tf.random_normal([2, 3], stddev=1), name="w1")
    -   w2 = tf.Variable(tf.random_normal([2, 3], dtype=tf.float64, stddev=1),
    -                       name="w2")
    -   w1.assign(w2)
    -   '''
    -   程序将报错:
    -   TypeError: Input 'value' of 'Assign' Op has type float64 that does not match type float32 of argument 'ref'.
    -   '''
    -   w1 = tf.Variable(tf.random_normal([2, 3], stddev=1), name="w1")
    -   w2 = tf.Variable(tf.random_normal([2, 2], stddev=1), name="w2")
    -   # 下面这句会报维度不匹配的错误: ValueError: Shapes (2, 3) and (2, 2) are not compatible
    -   tf.assign(w1, w2)
    -   # 这一句可以被成功执行。
    -   tf.assign(w1, w2, validate_shape=False)
                -3.4.4 通过TensorFlow训练神经网络模型
    -   x = tf.constant([[0.7, 0.9]])
    -   import tensorflow as tf
    -   w1 = tf.Variable(tf.random_normal([2, 3], stddev=1))
    -   w2 = tf.Variable(tf.random_normal([3, 1], stddev=1))
    -   # 定义placeholder作为存放输入数据的地方。这里维度也不一定要定义。 但如果维度是确定的,那么给出维度可以降低出错的概率。
    -   x = tf.placeholder(tf.float32, shape=(1, 2), name="input")
    -   a = tf.matmul(x, w1)
    -   y = tf.matmul(a, w2)
    -   sess = tf.Session()
    -   init_op = tf.initialize_all_variables()
    -   sess.run(init_op)
    -   # 下面一行将报错:InvalidArgumentError: You must feed a value for placeholder  tensor 'input_1' with dtype float and shape [1,2]
    -   print(sess.run(y))
    -   # 下面一行将会得到和3.4.2小节中一样的输出结果:[[3.95757794]]
    -   print(sess.run(y, feed_dict={x: [[0.7,0.9]]}))
    -   x = tf.placeholder(tf.float32, shape=(3, 2), name="input")
    -   … # 中间部分和上面的样例程序一样。 因为x在定义时指定了n为3,所以在运行前向传播过程时需要提供3个样例数据。
    -   print(sess.run(y, feed_dict={x: [[0.7,0.9], [0.1,0.4], [0.5,0.8]]}))
    -   '''
    -   输出结果为:
    -   [[ 3.95757794]
    -    [ 1.15376544]
    -    [ 3.16749191]]
    -   '''
    -   # 定义损失函数来刻画预测值与真实值得差距。
    -   cross_entropy = -tf.reduce_mean(
    -       y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
    -   # 定义学习率,在第4章中将更加具体的介绍学习率。
    -   learning_rate = 0.001
    -   # 定义反向传播算法来优化神经网络中的参数。
    -   train_step =\
    -       tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)
                -3.4.5 完整神经网络样例程序
    -   import tensorflow as tf
    -   # NumPy是一个科学计算的工具包,这里通过NumPy工具包生成模拟数据集。
    -   from numpy.random import RandomState
    -   # 定义训练数据batch的大小。
    -   batch_size = 8
    -   # 定义神经网络的参数,这里还是沿用3.4.2小节中给出的神经网络结构。
    -   w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1))
    -   w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))
    -   # 在shape的一个维度上使用None可以方便使用不同的batch大小。在训练时需要把数据分 成比较小的batch,但是在测试时,可以一次性使用全部的数据。当数据集比较小时这样比较
    -   # 方便测试,但数据集比较大时,将大量数据放入一个batch可能会导致内存溢出。
    -   x = tf.placeholder(tf.float32, shape=(None, 2), name='x-input')
    -   y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')
    -   # 定义神经网络前向传播的过程。
    -   a = tf.matmul(x, w1)
    -   y = tf.matmul(a, w2)
    -   # 定义损失函数和反向传播的算法。
    -   cross_entropy = -tf.reduce_mean(
    -       y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
    -   train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
    -   # 通过随机数生成一个模拟数据集。
    -   rdm = RandomState(1)
    -   dataset_size = 128
    -   X = rdm.rand(dataset_size, 2)
    -   # 定义规则来给出样本的标签。在这里所有x1+x2<1的样例都被认为是正样本(比如零件合格), 而其他为负样本(比如零件不合格)。和TensorFlow游乐场中的表示法不大一样的地方是,
    -   # 在这里使用0来表示负样本,1来表示正样本。大部分解决分类问题的神经网络都会采用 0和1的表示方法。
    -   Y = [[int(x1+x2 < 1)] for (x1, x2) in X]
    -   # 创建一个会话来运行TensorFlow程序。
    -   with tf.Session() as sess:
    -       init_op = tf.initialize_all_variables()
    -       # 初始化变量。
    -       sess.run(init_op)
    -       print sess.run(w1)
    -       print sess.run(w2)
    -       '''
    -       在训练之前神经网络参数的值:
    -       w1 = [[-0.81131822, 1.48459876, 0.06532937]
    -                 [-2.44270396, 0.0992484, 0.59122431]]
    -       w2 = [[-0.81131822], [1.48459876], [0.06532937]]
    -       '''
    -       # 设定训练的轮数。
    -       STEPS = 5000
    -       for i in range(STEPS):
    -           # 每次选取batch_size个样本进行训练。
    -           start = (i * batch_size) % dataset_size
    -           end =  min(start+batch_size, dataset_size)
    -           # 通过选取的样本训练神经网络并更新参数。
    -           sess.run(train_step,
    -                      feed_dict={x: X[start:end], y_: Y[start:end]})
    -           if i % 1000 == 0:
    -               # 每隔一段时间计算在所有数据上的交叉熵并输出。
    -               total_cross_entropy = sess.run(
    -                   cross_entropy, feed_dict={x: X, y_: Y})
    -               print("After %d training step(s), cross entropy on all data is %g" %
    -                          (i, total_cross_entropy))
    -               '''
    -               输出结果:
    -               After 0 training step(s), cross entropy on all data is 0.0674925
    -               After 1000 training step(s), cross entropy on all data is 0.0163385
    -               After 2000 training step(s), cross entropy on all data is 0.00907547
    -               After 3000 training step(s), cross entropy on all data is 0.00714436
    -               After 4000 training step(s), cross entropy on all data is 0.00578471
    -               通过这个结果可以发现随着训练的进行,交叉熵是逐渐变小的。交叉熵越小说明
    -               预测的结果和真实的结果差距越小。
    -               '''
    -       print sess.run(w1)
    -       print sess.run(w2)
    -       '''
    -       在训练之后神经网络参数的值:
    -       w1 = [[-1.9618274, 2.58235407, 1.68203783]
    -              [-3.4681716, 1.06982327, 2.11788988]]
    -       w2 = [[-1.8247149], [2.68546653], [1.41819501]]
    -       可以发现这两个参数的取值已经发生了变化,这个变化就是训练的结果。
    -       它使得这个神经网络能更好的拟合提供的训练数据。
    -       '''
            -小结
        -第4章 深层神经网络
            -4.1 深度学习与深层神经网络
                -4.1.1 线性模型的局限性
                -4.1.2 激活函数实现去线性化
    -   a = tf.nn.relu(tf.matmul(x, w1) + biases1)
    -   y = tf.nn.relu(tf.matmul(a, w2) + biases2)
                -4.1.3 多层网络解决异或运算
            -4.2 损失函数定义
                -4.2.1 经典损失函数
    -   cross_entropy = -tf.reduce_mean(
    -       y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
    -   v = tf.constant([[1.0, 2.0, 3.0],[4.0,5.0,6.0]])
    -   print tf.clip_by_value(v, 2.5, 4.5).eval()
    -   # 输出[[ 2.5  2.5  3.][ 4\.  4.5  4.5]]
    -   v = tf.constant([1.0, 2.0, 3.0])
    -   print tf.log(v).eval()
    -   # 输出[ 0\.   0.69314718  1.09861231]
    -   v1 = tf.constant([[1.0, 2.0], [3.0, 4.0]])
    -   v2 = tf.constant([[5.0, 6.0], [7.0, 8.0]])
    -   print (v1 * v2).eval()
    -   # 输出[[ 5\.  12.] [ 21\.  32.]]
    -   print tf.matmul(v1, v2).eval()
    -   # 输出[[ 19\. 22.] [ 43\.  50.]]
    -   v = tf.constant([[1.0, 2.0, 3.0],[4.0,5.0,6.0]])
    -   print tf.reduce_mean(v).eval()                                # 输出3.5
    -   cross_entropy = tf.nn.softmax_cross_entropy_with_logits(y, y_)
    -   mse = tf.reduce_mean(tf.square(y_ - y))
                -4.2.2 自定义损失函数
    -   loss = tf.reduce_sum(tf.select(tf.greater(v1, v2),
    -                                        (v1 - v2) * a, (v2 - v1) * b))
    -   import tensorflow as tf
    -   v1 = tf.constant([1.0, 2.0, 3.0, 4.0])
    -   v2 = tf.constant([4.0, 3.0, 2.0, 1.0])
    -   sess = tf.InteractiveSession()
    -   print tf.greater(v1, v2).eval()
    -   # 输出[False False  True  True]
    -   print tf.select(tf.greater(v1, v2), v1, v2).eval()
    -   # 输出[4\.  3\.  3\.  4.]
    -   sess.close()
    -   import tensorflow as tf
    -   from numpy.random import RandomState
    -   batch_size = 8
    -   # 两个输入节点。
    -   x = tf.placeholder(tf.float32, shape=(None, 2), name='x-input')
    -   # 回归问题一般只有一个输出节点。
    -   y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')
    -   # 定义了一个单层的神经网络前向传播的过程,这里就是简单加权和。
    -   w1 = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
    -   y = tf.matmul(x, w1)
    -   # 定义预测多了和预测少了的成本。
    -   loss_less = 10
    -   loss_more = 1
    -   loss = tf.reduce_sum(tf.select(tf.greater(y, y_),
    -                                        (y - y_) * loss_more,
    -                                        (y_ - y) * loss_less))
    -   train_step = tf.train.AdamOptimizer(0.001).minimize(loss)
    -   # 通过随机数生成一个模拟数据集。
    -   rdm = RandomState(1)
    -   dataset_size = 128
    -   X = rdm.rand(dataset_size, 2)
    -   # 设置回归的正确值为两个输入的和加上一个随机量。之所以要加上一个随机量是为了 加入不可预测的噪音,否则不同损失函数的意义就不大了,因为不同损失函数都会在能
    -   # 完全预测正确的时候最低。一般来说噪音为一个均值为0的小量,所以这里的噪音设置为 -0.05 ~ 0.05的随机数。
    -   Y = [[x1 + x2 + rdm.rand()/10.0-0.05] for (x1, x2) in X]
    -   # 训练神经网络。
    -   with tf.Session() as sess:
    -       init_op = tf.initialize_all_variables()
    -       sess.run(init_op)
    -       STEPS = 5000
    -       for i in range(STEPS):
    -           start = (i * batch_size) % dataset_size
    -           end =  min(start+batch_size, dataset_size)
    -           sess.run(train_step,
    -                      feed_dict={x: X[start:end], y_: Y[start:end]})
    -                      print sess.run(w1)
            -4.3 神经网络优化算法
    -   batch_size = n
    -   # 每次读取一小部分数据作为当前的训练数据来执行反向传播算法。
    -   x = tf.placeholder(tf.float32, shape=(batch_size, 2), name='x-input')
    -   y_ = tf.placeholder(tf.float32, shape=(batch_size, 1), name='y-input')
    -   # 定义神经网络结构和优化算法。
    -   loss = …
    -   train_step = tf.train.AdamOptimizer(0.001).minimize(loss)
    -   # 训练神经网络。
    -   with tf.Session() as sess:
    -       # 参数初始化。
    -        …
    -       # 迭代的更新参数。
    -   for i in range(STEPS):
    -           # 准备batch_size个训练数据。一般将所有训练数据随机打乱之后再选取可以得到 更好的优化效果。
    -           current_X, current_Y = …
    -           sess.run(train_step, feed_dict={x: current_X, y_: current_Y})
            -4.4 神经网络进一步优化
                -4.4.1 学习率的设置
    -   decayed_learning_rate = \
    -       learning_rate * decay_rate ^ (global_step / decay_ steps)
    -   global_step = tf.Variable(0)
    -   # 通过exponential_decay函数生成学习率。
    -   learning_rate = tf.train.exponential_decay(
    -       0.1, global_step, 100, 0.96, staircase=True)
    -   # 使用指数衰减的学习率。在minimize函数中传入global_step将自动更新 global_step参数,从而使得学习率也得到相应更新。
    -   learning_step = tf.train.GradientDescentOptimizer(learning_rate)\
    -             .minimize(...my loss..., global_step=global_step)
                -4.4.2 过拟合问题
    -   w= tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
    -   y = tf.matmul(x, w)
    -   loss = tf.reduce_mean(tf.square(y_ - y)) +
    -           tf.contrib.layers.l2_regularizer(lambda)(w)
    -   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))
    -       # 输出为(12+(-2)2+(-3)2+42)/2×0.5=7.5。
    -       print sess.run(tf.contrib.layers.l2_regularizer(.5)(weights))
    -   import tensorflow as tf
    -   # 获取一层神经网络边上的权重,并将这个权重的L2正则化损失加入名称为'losses'的集合中
    -   def get_weight(shape, lambda):
    -         # 生成一个变量。
    -         var = tf.Variable(tf.random_normal(shape), dtype = tf.float32)
    -         # add_to_collection函数将这个新生成变量的L2正则化损失项加入集合。 这个函数的第一个参数'losses'是集合的名字,第二个参数是要加入这个集合的内容。
    -         tf.add_to_collection(
    -             'losses',tf.contrib.layers.l2_regularizer(lambda)(var))
    -         # 返回生成的变量。
    -         return var
    -   x = tf.placeholder(tf.float32, shape=(None, 2))
    -   y_ = tf.placeholder(tf.float32, shape=(None, 1))
    -   batch_size = 8
    -   # 定义了每一层网络中节点的个数。
    -   layer_dimension = [2, 10, 10, 10, 1]
    -   # 神经网络的层数。
    -   n_layers = len(layer_dimension)
    -   # 这个变量维护前向传播时最深层的节点,开始的时候就是输入层。
    -   cur_layer = x
    -   # 当前层的节点个数。
    -   in_dimension = layer_dimension[0]
    -   # 通过一个循环来生成5层全连接的神经网络结构。
    -   for i in range(1, n_layers):
    -         # layer_dimension[i]为下一层的节点个数。
    -         out_dimension = layer_dimension[i]
    -         # 生成当前层中权重的变量,并将这个变量的L2正则化损失加入计算图上的集合。
    -         weight = get_weight([in_dimension, out_dimension], 0.001)
    -         bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))
    -     # 使用ReLU激活函数。
    -     cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
    -         # 进入下一层之前将下一层的节点个数更新为当前层节点个数。
    -         in_dimension = layer_dimension[i]
    -   # 在定义神经网络前向传播的同时已经将所有的L2正则化损失加入了图上的集合,  这里只需要计算刻画模型在训练数据上表现的损失函数。
    -   mse_loss = tf.reduce_mean(tf.square(y_ - cur_layer))
    -   # 将均方误差损失函数加入损失集合。
    -   tf.add_to_collection('losses', mse_loss)
    -   # get_collection返回一个列表,这个列表是所有这个集合中的元素。在这个样例中,  这些元素就是损失函数的不同部分,将它们加起来就可以得到最终的损失函数。
    -   loss = tf.add_n(tf.get_collection('losses'))
                -4.4.3 滑动平均模型
    -   import tensorflow as tf
    -   # 定义一个变量用于计算滑动平均,这个变量的初始值为0。注意这里手动指定了变量的 类型为tf.float32,因为所有需要计算滑动平均的变量必须是实数型。
    -   v1 = tf.Variable(0, dtype=tf.float32)
    -   # 这里step变量模拟神经网络中迭代的轮数,可以用于动态控制衰减率。
    -   step = tf.Variable(0, trainable=False)
    -   # 定义一个滑动平均的类(class)。初始化时给定了衰减率(0.99)和控制衰减率的变量step。
    -   ema = tf.train.ExponentialMovingAverage(0.99, step)
    -   # 定义一个更新变量滑动平均的操作。这里需要给定一个列表,每次执行这个操作时 这个列表中的变量都会被更新。
    -   maintain_averages_op = ema.apply([v1])
    -   with tf.Session() as sess:
    -       # 初始化所有变量。
    -       init_op = tf.initialize_all_variables()
    -       sess.run(init_op)
    -       # 通过ema.average(v1)获取滑动平均之后变量的取值。在初始化之后变量v1的值和v1的 滑动平均都为0。
    -       print sess.run([v1, ema.average(v1)])          #  输出[0.0, 0.0] 更新变量v1的值到5。
    -       sess.run(tf.assign(v1, 5))
    -       # 更新v1的滑动平均值。衰减率为min{0.99,(1+step)/(10+step)= 0.1}=0.1, 所以v1的滑动平均会被更新为0.1×0+0.9×5=4.5。
    -       sess.run(maintain_averages_op)
    -       print sess.run([v1, ema.average(v1)])         #  输出[5.0, 4.5] 更新step的值为10000。
    -       sess.run(tf.assign(step, 10000))
    -       # 更新v1的值为10。
    -       sess.run(tf.assign(v1, 10))
    -       # 更新v1的滑动平均值。衰减率为min{0.99,(1+step)/(10+step)  0.999}=0.99, 所以v1的滑动平均会被更新为0.99×4.5+0.01×10=4.555。
    -       sess.run(maintain_averages_op)
    -       print sess.run([v1, ema.average(v1)])
    -       #  输出[10.0, 4.5549998] 再次更新滑动平均值,得到的新滑动平均值为0.99×4.555+0.01×10=4.60945。
    -       sess.run(maintain_averages_op)
    -       print sess.run([v1, ema.average(v1)])
    -       # 输出[10.0, 4.6094499]
            -小结
        -第5章 MNIST数字识别问题
            -5.1 MNIST数据处理
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   # 载入MNIST数据集,如果指定地址/path/to/MNIST_data下没有已经下载好的数据, 那么TensorFlow会自动从表5-1给出的网址下载数据。
    -   mnist = input_data.read_data_sets("/path/to/MNIST_data/", one_hot=True)
    -   # 打印Training data size:  55000。
    -   print "Training data size: ", mnist.train.num_examples
    -   # 打印Validating data size:  5000。
    -   print "Validating data size: ", mnist.validation.num_examples
    -   # 打印Testing data size:  10000。
    -   print "Testing data size: ", mnist.test.num_examples
    -   # 打印Example training data:  [ 0\.  0\.  0\.  …    0.380   0.376   …   0\.  ]。
    -   print "Example training data: ", mnist.train.images[0]
    -   # 打印Example training data label:   [ 0\.  0\.  0\.  0\.  0\.  0\.  0\.  1\.  0\.  0.]
    -   print "Example training data label: ", mnist.train.labels[0]
    -   batch_size = 100
    -   xs, ys = mnist.train.next_batch(batch_size)
    -   # 从train的集合中选取batch_size个训练数据。
    -   print "X shape:", xs.shape
    -   # 输出X shape: (100, 784)。
    -   print "Y shape:", ys.shape
    -   # 输出Y shape: (100, 10)。
            -5.2 神经网络模型训练及不同模型结果对比
                -5.2.1 TensorFlow训练神经网络
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   # MNIST数据集相关的常数。
    -   INPUT_NODE = 784     # 输入层的节点数。对于MNIST数据集,这个就等于图片的像素。
    -   OUTPUT_NODE = 10     # 输出层的节点数。这个等于类别的数目。因为在MNIST数据集中 需要区分的是0~9这10个数字,所以这里输出层的节点数为10。
    -   # 配置神经网络的参数。
    -   LAYER1_NODE = 500     # 隐藏层节点数。这里使用只有一个隐藏层的网络结构作为样例。 这个隐藏层有500个节点。
    -   BATCH_SIZE = 100      # 一个训练batch中的训练数据个数。数字越小时,训练过程越接近 随机梯度下降;数字越大时,训练越接近梯度下降。
    -   LEARNING_RATE_BASE = 0.8          # 基础的学习率。
    -   LEARNING_RATE_DECAY = 0.99           # 学习率的衰减率。
    -   REGULARIZATION_RATE = 0.0001         # 描述模型复杂度的正则化项在损失函数中的系数。
    -   TRAINING_STEPS = 30000              # 训练轮数。
    -   MOVING_AVERAGE_DECAY = 0.99          # 滑动平均衰减率。 一个辅助函数,给定神经网络的输入和所有参数,计算神经网络的前向传播结果。在这里
    -   # 定义了一个使用ReLU激活函数的三层全连接神经网络。通过加入隐藏层实现了多层网络结构, 通过ReLU激活函数实现了去线性化。在这个函数中也支持传入用于计算参数平均值的类,
    -   # 这样方便在测试时使用滑动平均模型。
    -   def inference(input_tensor, avg_class, weights1, biases1,
    -                    weights2, biases2):
    -       # 当没有提供滑动平均类时,直接使用参数当前的取值。
    -       if avg_class == None:
    -          # 计算隐藏层的前向传播结果,这里使用了ReLU激活函数。
    -          layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1)
    -          # 计算输出层的前向传播结果。因为在计算损失函数时会一并计算softmax函数,  所以这里不需要加入激活函数。而且不加入softmax不会影响预测结果。因为预测时
    -            # 使用的是不同类别对应节点输出值的相对大小,有没有softmax层对最后分类结果的 计算没有影响。于是在计算整个神经网络的前向传播时可以不加入最后的softmax层。
    -          return tf.matmul(layer1, weights2) + biases2
    -       else:
    -          # 首先使用avg_class.average函数来计算得出变量的滑动平均值,  然后再计算相应的神经网络前向传播结果。
    -          layer1 = tf.nn.relu(
    -                tf.matmul(input_tensor, avg_class.average(weights1)) +
    -                avg_class.average(biases1))
    -          return tf.matmul(layer1, avg_class.average(weights2)) +
    -                    avg_class. average(biases2)
    -   # 训练模型的过程。
    -   def train(mnist):
    -       x = tf.placeholder(tf.float32, [None, INPUT_NODE], name='x-input')
    -       y_ = tf.placeholder(tf.float32, [None, OUTPUT_NODE], name='y-input')
    -       # 生成隐藏层的参数。
    -       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]))
    -       # 计算在当前参数下神经网络前向传播的结果。这里给出的用于计算滑动平均的类为None, 所以函数不会使用参数的滑动平均值。
    -       y = inference(x, None, weights1, biases1, weights2, biases2)
    -       # 定义存储训练轮数的变量。这个变量不需要计算滑动平均值,所以这里指定这个变量为 不可训练的变量(trainable=Fasle)。在使用TensorFlow训练神经网络时,
    -       # 一般会将代表训练轮数的变量指定为不可训练的参数。
    -       global_step = tf.Variable(0, trainable=False)
    -       # 给定滑动平均衰减率和训练轮数的变量,初始化滑动平均类。在第4章中介绍过给 定训练轮数的变量可以加快训练早期变量的更新速度。
    -       variable_averages = tf.train.ExponentialMovingAverage(
    -           MOVING_AVERAGE_DECAY, global_step)
    -       # 在所有代表神经网络参数的变量上使用滑动平均。其他辅助变量(比如global_step)就 不需要了。 tf.trainable_variables返回的就是图上集合
    -       # GraphKeys.TRAINABLE_VARIABLES中的元素。这个集合的元素就是所有没有指定 trainable=False的参数。
    -       variables_averages_op = variable_averages.apply(
    -           tf.trainable_variables())
    -       # 计算使用了滑动平均之后的前向传播结果。第4章中介绍过滑动平均不会改变变量本身的 取值,而是会维护一个影子变量来记录其滑动平均值。所以当需要使用这个滑动平均值时,
    -       # 需要明确调用average函数。
    -       average_y = inference(
    -           x, variable_averages, weights1, biases1, weights2, biases2)
    -       # 计算交叉熵作为刻画预测值和真实值之间差距的损失函数。这里使用了TensorFlow中提 供的sparse_softmax_cross_entropy_with_logits函数来计算交叉熵。当分类
    -       # 问题只有一个正确答案时,可以使用这个函数来加速交叉熵的计算。MNIST问题的图片中 只包含了0~9中的一个数字,所以可以使用这个函数来计算交叉熵损失。这个函数的第一个
    -       # 参数是神经网络不包括softmax层的前向传播结果,第二个是训练数据的正确答案。因为 标准答案是一个长度为10的一维数组,而该函数需要提供的是一个正确答案的数字,所以需
    -       # 要使用tf.argmax函数来得到正确答案对应的类别编号。
    -       cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
    -           y, tf.argmax(y_, 1))
    -       # 计算在当前batch中所有样例的交叉熵平均值。
    -       cross_entropy_mean = tf.reduce_mean(cross_entropy)
    -       # 计算L2正则化损失函数。
    -       regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
    -       # 计算模型的正则化损失。一般只计算神经网络边上权重的正则化损失,而不使用偏置项。
    -       regularization = regularizer(weights1) + regularizer(weights2)
    -       # 总损失等于交叉熵损失和正则化损失的和。
    -       loss = cross_entropy_mean + regularizaztion
    -       # 设置指数衰减的学习率。
    -       learning_rate = tf.train.exponential_decay(
    -          LEARNING_RATE_BASE,        # 基础的学习率,随着迭代的进行,更新变量时使用的 学习率在这个基础上递减。
    -          global_step,              # 当前迭代的轮数。
    -          mnist.train.num_examples / BATCH_SIZE,     # 过完所有的训练数据需要的迭 代次数。
    -          LEARNING_RATE_DECAY)       # 学习率衰减速度。 使用tf.train.GradientDescentOptimizer优化算法来优化损失函数。注意这里损失函数
    -   # 包含了交叉熵损失和L2正则化损失。
    -   train_step=tf.train.GradientDescentOptimizer(learning_rate)\
    -                   .minimize(loss, global_step=global_step)
    -   # 在训练神经网络模型时,每过一遍数据既需要通过反向传播来更新神经网络中的参数,  又要更新每一个参数的滑动平均值。为了一次完成多个操作,TensorFlow提供了
    -   # tf.control_dependencies和tf.group两种机制。下面两行程序和 train_op = tf.group(train_step, variables_averages_op)是等价的。
    -   with tf.control_dependencies([train_step, variables_averages_op]):
    -       train_op = tf.no_op(name='train')
    -   # 检验使用了滑动平均模型的神经网络前向传播结果是否正确。tf.argmax(average_y, 1) 计算每一个样例的预测答案。其中average_y是一个batch_size * 10的二维数组,每一行
    -   # 表示一个样例的前向传播结果。tf.argmax的第二个参数“1”表示选取最大值的操作仅在第一 个维度中进行,也就是说,只在每一行选取最大值对应的下标。于是得到的结果是一个长度为
    -   # batch的一维数组,这个一维数组中的值就表示了每一个样例对应的数字识别结果。tf.equal 判断两个张量的每一维是否相等,如果相等返回True,否则返回False。
    -   correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_,1))
    -   # 这个运算首先将一个布尔型的数值转换为实数型,然后计算平均值。这个平均值就是模型在这 一组数据上的正确率。
    -   accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    -   # 初始化会话并开始训练过程。
    -   with tf.Session() as sess:
    -       tf.initialize_all_variables().run()
    -       # 准备验证数据。一般在神经网络的训练过程中会通过验证数据来大致判断停止的 条件和评判训练的效果。
    -       validate_feed = {x: mnist.validation.images,
    -                            y_: mnist.validation. labels}
    -       # 准备测试数据。在真实的应用中,这部分数据在训练时是不可见的,这个数据只是作为模 型优劣的最后评价标准。
    -       test_feed = {x: mnist.test.images, y_: mnist.test.labels}
    -       # 迭代地训练神经网络。
    -       for i in range(TRAINING_STEPS):
    -           # 每1000轮输出一次在验证数据集上的测试结果。
    -           if i % 1000 == 0:
    -           # 计算滑动平均模型在验证数据上的结果。因为MNIST数据集比较小,所以一次 可以处理所有的验证数据。为了计算方便,本样例程序没有将验证数据划分为更
    -           # 小的batch。当神经网络模型比较复杂或者验证数据比较大时,太大的batch 会导致计算时间过长甚至发生内存溢出的错误。
    -                 validate_acc = sess.run(accuracy, feed_dict=validate_feed)
    -                 print("After %d training step(s), validation accuracy "
    -                        "using average model is %g " % (i, validate_acc))
    -           # 产生这一轮使用的一个batch的训练数据,并运行训练过程。
    -          xs, ys = mnist.train.next_batch(BATCH_SIZE)
    -          sess.run(train_op, feed_dict={x: xs, y_: ys})
    -       # 在训练结束之后,在测试数据上检测神经网络模型的最终正确率。
    -       test_acc = sess.run(accuracy, feed_dict=test_feed)
    -       print("After %d training step(s), test accuracy using average "
    -              "model is %g" % (TRAINING_STEPS, test_acc))
    -   # 主程序入口。
    -   def main(argv=None):
    -       # 声明处理MNIST数据集的类,这个类在初始化时会自动下载数据。
    -       mnist = input_data.read_data_sets("/tmp/data", one_hot=True)
    -       train(mnist)
    -   # TensorFlow提供的一个主程序入口,tf.app.run会调用上面定义的main函数。
    -   if __name__ == '__main__':
    -       tf.app.run()
    -:
    -   Extracting /tmp/data/train-images-idx3-ubyte.gz
    -   Extracting /tmp/data/train-labels-idx1-ubyte.gz
    -   Extracting /tmp/data/t10k-images-idx3-ubyte.gz
    -   Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
    -   After 0 training step(s), validation accuracy on average model is 0.105
    -   After 1000 training step(s), validation accuracy using average model is 0.9774
    -   After 2000 training step(s), validation accuracy using average model is 0.9816
    -   After 3000 training step(s), validation accuracy using average model is 0.9834
    -   After 4000 training step(s), validation accuracy using average model is 0.9832
    -   ...
    -   After 27000 training step(s), validation accuracy using average model is 0.984
    -   After 28000 training step(s), validation accuracy using average model is 0.985
    -   After 29000 training step(s), validation accuracy using average model is 0.985
    -   After 29999 training step(s), validation accuracy using average model is 0.985
    -   After 30000 training step(s), test accuracy on average model is 0.984…………………….
                -书名页
    -5.2.2 使用验证数据集判断模型效果
    -       # 计算滑动平均模型在测试数据和验证数据上的正确率。
    -       validate_acc = sess.run(accuracy, feed_dict=validate_feed)
    -       test_acc = sess.run(accuracy, feed_dict=test_feed)
    -       # 输出正确率信息。
    -       print("After %d training step(s), validation accuracy using average "
    -              "model is %g, test accuracy using average model is %g"  %
    -                  (i, validate_acc, test _acc))
                -书名页
    -5.2.3 不同模型效果比较
    -,使用不同优化方法,经过30000轮训练迭代后,得到的最终模型的正确率 [(5)](part0012_split_006.html#ch5)
    -。图5-3给出的结果中包含了使用所有优化方法训练得到的模型和不用其中某一项优化方法训练得到的模型。通过这种方式,可以有效验证每一项优化方法的效果。
    -的变化趋势。图5-5显示了不同迭代轮数时,正确率与衰减之后的学习率的变化趋势。
    -   train_step = tf.train.GradientDescentOptimizer(learning_rate)\
    -                     .minimize(cross_entropy_mean, global_step=global_step)
    -2正则化损失的和。以下代码给出了这个模型优化函数的声明语句。
    -   loss = cross_entropy_mean + regularaztion
    -   train_step = tf.train.GradientDescentOptimizer(learning_rate)\
    -                     .minimize(loss, global_step=global_step)
            - 5.3 变量管理
    -   def inference(input_tensor, avg_class, weights1, biases1, weights2, biases2):
    -   # 下面这两个定义是等价的。
    -   v = tf.get_variable("v", shape=[1],
    -                           initializer=tf.constant_initializer(1.0))
    -   v = tf.Variable(tf.constant(1.0, shape=[1]), name="v")
    -   # 在名字为foo的命名空间内创建名字为v的变量。
    -   with tf.variable_scope("foo"):
    -       v = tf.get_variable(
    -           "v", [1], initializer=tf.constant_initializer(1.0))
    -   # 因为在命名空间foo中已经存在名字为v的变量,所有下面的代码将会报错: Variable foo/v already exists, disallowed. Did you mean to set reuse=True
    -   # in VarScope?
    -   with tf.variable_scope("foo"):
    -        v = tf.get_variable("v", [1])
    -   # 在生成上下文管理器时,将参数reuse设置为True。这样tf.get_variable函数将直接获取 已经声明的变量。
    -   with tf.variable_scope("foo", reuse=True):
    -       v1 = tf.get_variable("v", [1])
    -       print v == v1    # 输出为True,代表v,v1代表的是相同的TensorFlow中变量。 将参数reuse设置为True时,tf.variable_scope将只能获取已经创建过的变量。因为在
    -   # 命名空间bar中还没有创建变量v,所以下面的代码将会报错: Variable bar/v does not exist, disallowed. Did you mean to set reuse=None
    -   # in VarScope?
    -   with tf.variable_scope("bar", reuse=True):
    -        v = tf.get_variable("v", [1])
    -   with tf.variable_scope("root"):
    -       # 可以通过tf.get_variable_scope().reuse函数来获取当前上下文管理器中reuse参 数的取值。
    -       print tf.get_variable_scope().reuse    # 输出False,即最外层reuse是False。
    -       with tf.variable_scope("foo", reuse=True):    # 新建一个嵌套的上下文管理器, 并指定reuse为True。
    -           print tf.get_variable_scope().reuse        # 输出True。
    -           with tf.variable_scope("bar"):              # 新建一个嵌套的上下文管理器但 不指定reuse,这时reuse
    -                                                             # 的取值会和外面一层保持一致。
    -               print tf.get_variable_scope().reuse     # 输出True。
    -       print tf.get_variable_scope().reuse            # 输出False。退出reuse设置 为True的上下文之后
    -                                                             # reuse的值又回到了False。
    -   v1 = tf.get_variable("v", [1])
    -   print v1.name        # 输出v:0。“v”为变量的名称,“:0”表示这个变量是生成变量这个运算 的第一个结果。
    -   with tf.variable_scope("foo"):
    -       v2 = tf.get_variable("v", [1])
    -       print v2.name    # 输出foo/v:0。在tf.variable_scope中创建的变量,名称前面会 加入命名空间的名称,并通过/来分隔命名空间的名称和变量的名称。
    -   with tf.variable_scope("foo"):
    -       with tf.variable_scope("bar"):
    -           v3 = tf.get_variable("v", [1])
    -          print v3.name       # 输出foo/bar/v:0。命名空间可以嵌套,同时变量的名称也会加 入所有命名空间的名称作为前缀。
    -       v4 = tf.get_variable("v1", [1])
    -       print v4.name       # 输出foo/v1:0。当命名空间退出之后,变量名称也就不会再被加入 其前缀了。
    -   # 创建一个名称为空的命名空间,并设置reuse=True。
    -   with tf.variable_scope("", reuse=True):
    -       v5 = tf.get_variable("foo/bar/v", [1])    # 可以直接通过带命名空间名称的变量名 来获取其他命名空间下的变量。比如这
    -                                                        # 里通过指定名称foo/bar/v来获取在 命名空间foo/bar/中创建的变量。
    -       print v5 == v3                                 # 输出True。
    -       v6 = tf.get_variable("foo/v1", [1])
    -       print v6 == v4                                 # 输出True。
    -   def inference(input_tensor, reuse=False):
    -       # 定义第一层神经网络的变量和前向传播过程。
    -       with tf.variable_scope('layer1', reuse=reuse):
    -           # 根据传进来的reuse来判断是创建新变量还是使用已经创建好的。在第一次构造网 络时需要创建新的变量,以后每次调用这个函数都直接使用reuse=True就不需
    -           # 要每次将变量传进来了。
    -           weights = tf.get_variable("weights", [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 = tf.get_variable("weights", [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
    -   x = tf.placeholder(tf.float32, [None, INPUT_NODE], name='x-input')
    -   y = inference(x)
    -   # 在程序中需要使用训练好的神经网络进行推导时,可以直接调用inference(new_x, True)。 如果需要使用滑动平均模型可以参考5.2.1小节中使用的代码,把计算滑动平均的类传到
    -   # inference函数中即可。获取或者创建变量的部分不需要改变。
    -   new_x = ...
    -   new_y = inference(new_x, True)
            - 5.4 TensorFlow模型持久化
                -书名页
    -5.4.1 持久化代码实现
    -   import tensorflow as tf
    -   # 声明两个变量并计算它们的和。
    -   v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="v1")
    -   v2 = tf.Variable(tf.constant(2.0, shape=[1]), name="v2")
    -   result = v1 + v2
    -   init_op = tf.initialize_all_variables()
    -   # 声明tf.train.Saver类用于保存模型。
    -   saver = tf.train.Saver()
    -   with tf.Session() as sess:
    -       sess.run(init_op)
    -       # 将模型保存到/path/to/model/model.ckpt文件。
    -       saver.save(sess, "/path/to/model/model.ckpt")
    -   import tensorflow as tf
    -   # 使用和保存模型代码中一样的方式来声明变量。
    -   v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="v1")
    -   v2 = tf.Variable(tf.constant(2.0, shape=[1]), name="v2")
    -   result = v1 + v2
    -   saver = tf.train.Saver()
    -   with tf.Session() as sess:
    -       # 加载已经保存的模型,并通过已经保存的模型中变量的值来计算加法。
    -       saver.restore(sess, "/path/to/model/model.ckpt")
    -       print sess.run(result)
    -   import tensorflow as tf
    -   # 直接加载持久化的图。
    -   saver = tf.train.import_meta_graph(
    -       "/path/to/model/model.ckpt/model.ckpt.meta")
    -   with tf.Session() as sess:
    -       saver.restore(sess, "/path/to/model/model.ckpt")
    -       # 通过张量的名称来获取张量。
    -       print sess.run(tf.get_default_graph().get_tensor_by_name("add:0"))
    -       # 输出[ 3.]
    -   tensorflow.python.framework.errors.FailedPreconditionError: Attempting to use uninitialized value v2
    -   # 这里声明的变量名称和已经保存的模型中变量的名称不同。
    -   v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="other-v1")
    -   v2 = tf.Variable(tf.constant(2.0, shape=[1]), name="other-v2")
    -   # 如果直接使用tf.train.Saver()来加载模型会报变量找不到的错误。下面显示了报错信息: tensorflow.python.framework.errors.NotFoundError: Tensor name "other-v2"
    -   # not found in checkpoint files /path/to/model/model.ckpt 使用一个字典(dictionary)来重命名变量可以就可以加载原来的模型了。这个字典指定了
    -   # 原来名称为v1的变量现在加载到变量v1中(名称为other-v1),名称为v2的变量 加载到变量v2中(名称为other-v2)。
    -   saver = tf.train.Saver({"v1": v1, "v2": v2})
    -   import tensorflow as tf
    -   v = tf.Variable(0, dtype=tf.float32, name="v")
    -   # 在没有申明滑动平均模型时只有一个变量v,所以下面的语句只会输出“v:0”。
    -   for variables in tf.all_variables():
    -       print variables.name
    -   ema = tf.train.ExponentialMovingAverage(0.99)
    -   maintain_averages_op = ema.apply(tf.all_variables())
    -   # 在申明滑动平均模型之后,TensorFlow会自动生成一个影子变量 v/ExponentialMoving Average。于是下面的语句会输出
    -   # “v:0”和“v/ExponentialMovingAverage:0”。
    -   for variables in tf.all_variables():
    -       print variables.name
    -   saver = tf.train.Saver()
    -   with tf.Session() as sess:
    -       init_op = tf.initialize_all_variables()
    -       sess.run(init_op)
    -       sess.run(tf.assign(v, 10))
    -       sess.run(maintain_averages_op)
    -       # 保存时,TensorFlow会将v:0和v/ExponentialMovingAverage:0两个变量都存下来。
    -       saver.save(sess, "/path/to/model/model.ckpt")
    -       print sess.run([v, ema.average(v)])             # 输出[10.0, 0.099999905]
    -   v = tf.Variable(0, dtype=tf.float32, name="v")
    -   # 通过变量重命名将原来变量v的滑动平均值直接赋值给v。
    -   saver = tf.train.Saver({"v/ExponentialMovingAverage": v})
    -   with tf.Session() as sess:
    -       saver.restore(sess, "/path/to/model/model.ckpt")
    -      print sess.run(v) # 输出 0.099999905,这个值就是原来模型中变量v的滑动平均值。
    -   import tensorflow as tf
    -   v = tf.Variable(0, dtype=tf.float32, name="v")
    -   ema = tf.train.ExponentialMovingAverage(0.99)
    -   # 通过使用variables_to_restore函数可以直接生成上面代码中提供的字典 {"v/ExponentialMovingAverage": v}。
    -   # 以下代码会输出: {'v/ExponentialMovingAverage': }
    -   # 其中后面的Variable类就代表了变量v。
    -   print ema.variables_to_restore()
    -   saver = tf.train.Saver(ema.variables_to_restore())
    -   with tf.Session() as sess:
    -       saver.restore(sess, "/path/to/model/model.ckpt")
    -       print sess.run(v)  # 输出 0.099999905,即原来模型中变量v的滑动平均值。
    -   import tensorflow as tf
    -   from tensorflow.python.framework import graph_util
    -   v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="v1")
    -   v2 = tf.Variable(tf.constant(2.0, shape=[1]), name="v2")
    -   result = v1 + v2
    -   init_op = tf.initialize_all_variables()
    -   with tf.Session() as sess:
    -      sess.run(init_op)
    -      # 导出当前计算图的GraphDef部分,只需要这一部分就可以完成从输入层到输出层的计算 过程。
    -      graph_def = tf.get_default_graph().as_graph_def()
    -      # 将图中的变量及其取值转化为常量,同时将图中不必要的节点去掉。在5.4.2小节中将会看 到一些系统运算也会被转化为计算图中的节点(比如变量初始化操作)。如果只关心程序中定
    -      # 义的某些计算时,和这些计算无关的节点就没有必要导出并保存了。在下面一行代码中,最 后一个参数['add']给出了需要保存的节点名称。add节点是上面定义的两个变量相加的
    -      # 操作。注意这里给出的是计算节点的名称,所以没有后面的:0 [(7)](part0012_split_006.html#ch7)
    -      output_graph_def = graph_util.convert_variables_to_constants(
    -           sess, graph_def, ['add'])
    -      # 将导出的模型存入文件。
    -      with tf.gfile.GFile("/path/to/model/combined_model.pb", "wb") as f:
    -          f.write(output_graph_def.SerializeToString())
    -   import tensorflow as tf
    -   from tensorflow.python.platform import gfile
    -   with tf.Session() as sess:
    -      model_filename = "/path/to/model/combined_model.pb"
    -      # 读取保存的模型文件,并将文件解析成对应的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)
                -书名页
    -5.4.2 持久化原理及数据格式
    -。MetaGraphDef中的内容就构成了TensorFlow持久化时的第一个文件。以下代码给出了MetaGraphDef类型的定义。
    -   message MetaGraphDef {
    -       MetaInfoDef meta_info_def = 1;
    -       GraphDef graph_def = 2;
    -       SaverDef saver_def = 3;
    -       map>string, CollectionDef> collection_def = 4;
    -       map>string, SignatureDef> signature_def = 5;
    -   }
    -   import tensorflow as tf
    -   # 定义变量相加的计算。
    -   v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="v1")
    -   v2 = tf.Variable(tf.constant(2.0, shape=[1]), name="v2")
    -   result1 = v1 + v2
    -   saver = tf.train.Saver()
    -   # 通过export_meta_graph函数导出TensorFlow计算图的元图,并保存为json格式。
    -   saver.export_meta_graph("/path/to/model.ckpt.meda.json",  as_text=True)
    -   message MetaInfoDef {
    -       string meta_graph_version = 1;
    -       OpList stripped_op_list = 2;
    -       google.protobuf.Any any_info = 3;
    -       repeated string tags = 4;
    -   }
    -   message OpDef {
    -       string name = 1;
    -       repeated ArgDef input_arg = 2;
    -       repeated ArgDef output_arg = 3;
    -       repeated AttrDef attr = 4;
    -       string summary = 5;
    -       string description = 6;
    -       OpDeprecation deprecation = 8;
    -       bool is_commutative = 18;
    -       bool is_aggregate = 16
    -       bool is_stateful = 17;
    -       bool allows_uninitialized_input = 19;
    -   };
    -   op {
    -       name: "Add"
    -       input_arg {
    -           name: "x"
    -           type_attr: "T"
    -       }
    -       input_arg {
    -           name: "y"
    -           type_attr: "T"
    -       }
    -       output_arg {
    -           name: "z"
    -           type_attr: "T"
    -       }
    -       attr {
    -           name: "T"
    -           type: "type"
    -           allowed_values {
    -               list {
    -                   type: DT_HALF
    -                   type: DT_FLOAT
    -                   ...
    -               }
    -           }
    -      }
    -   }
    -   message GraphDef {
    -     repeated NodeDef node = 1;
    -     VersionDef versions = 4;
    -   };
    -   message NodeDef {
    -     string name = 1;
    -     string op = 2;
    -     repeated string input = 3;
    -     string device = 4;
    -     map attr = 5;
    -   };
    -   graph_def {
    -    node {
    -      name: "v1"
    -      op: "Variable"
    -      attr {
    -        key: "_output_shapes"
    -        value {
    -          list { shape {  dim {  size: 1  }  }  }
    -        }
    -      }
    -      attr {
    -        key: "dtype"
    -        value {
    -          type: DT_FLOAT
    -        }
    -      }
    -      ...
    -    }
    -    node {
    -      name: "add"
    -      op: "Add"
    -      input: "v1/read"
    -      input: "v2/read"
    -      ...
    -    }
    -    node {
    -      name: "save/control_dependency"
    -      op: "Identity"
    -      ...
    -    }
    -    versions {
    -      producer: 9
    -    }
    -   }
    -   message SaverDef {
    -     string filename_tensor_name = 1;
    -     string save_tensor_name = 2;
    -     string restore_op_name = 3;
    -     int32 max_to_keep = 4;
    -     bool sharded = 5;
    -     float keep_checkpoint_every_n_hours = 6;
    -     enum CheckpointFormatVersion {
    -       LEGACY = 0;
    -       V1 = 1;
    -       V2 = 2;
    -     }
    -     CheckpointFormatVersion version = 7;
    -   }
    -   saver_def {
    -     filename_tensor_name: "save/Const:0"
    -     save_tensor_name: "save/control_dependency:0"
    -     restore_op_name: "save/restore_all"
    -     max_to_keep: 5
    -     keep_checkpoint_every_n_hours: 10000.0
    -   }
    -小时可以在max_to_keep的基础上多保存一个模型。
    -   message CollectionDef {
    -     message NodeList {
    -       repeated string value = 1;
    -     }
    -     message BytesList {
    -       repeated bytes value = 1;
    -     }
    -     message Int64List {
    -       repeated int64 value = 1 [packed = true];
    -     }
    -     message FloatList {
    -       repeated float value = 1 [packed = true];
    -     }
    -     message AnyList {
    -       repeated google.protobuf.Any value = 1;
    -     }
    -     oneof kind {
    -       NodeList node_list = 1;
    -       BytesList bytes_list = 2;
    -       Int64List int64_list = 3;
    -       FloatList float_list = 4;
    -       AnyList any_list = 5;
    -     }
    -   }
    -   collection_def {
    -    key: "trainable_variables"
    -    value {
    -      bytes_list {
    -        value: "\n\004v1:0\022\tv1/Assign\032\tv1/read:0"
    -        value: "\n\004v2:0\022\tv2/Assign\032\tv2/read:0"
    -      }
    -    }
    -   }
    -   collection_def {
    -    key: "variables"
    -    value {
    -      bytes_list {
    -        value: "\n\004v1:0\022\tv1/Assign\032\tv1/read:0"
    -        value: "\n\004v2:0\022\tv2/Assign\032\tv2/read:0"
    -      }
    -    }
    -。
    -   import tensorflow as tf
    -   # tf.train.NewCheckpointReader可以读取checkpoint文件中保存的所有变量。
    -   reader = tf.train.NewCheckpointReader('/path/to/model/model.ckpt')
    -   # 获取所有变量列表。这个是一个从变量名到变量维度的字典。
    -   all_variables = reader.get_variable_to_shape_map()
    -   for variable_name in all_variables:
    -       # variable_name为变量名称,all_variables[variable_name]为变量的维度。
    -       print variable_name, all_variables[variable_name]
    -   # 获取名称为v1的变量的取值。
    -   print "Value for variable v1 is ", reader.get_tensor("v1")
    -   '''
    -   这个程序将输出:
    -   v1 [1]                                             # 变量v1的维度为[1]。
    -   v2 [1]                                             # 变量v2的维度为[1]。
    -   Value for variable v1 is [ 1.]                # 变量v1的取值为1。
    -   '''
    -   message CheckpointState {
    -     string model_checkpoint_path = 1;
    -     repeated string all_model_checkpoint_paths = 2;
    -   }
    -   model_checkpoint_path: "/path/to/model/model.ckpt"
    -   all_model_checkpoint_paths: "/path/to/model/model.ckpt"
            - 5.5 TensorFlow最佳实践样例程序
    -   # -*- coding: utf-8 -*-
    -   import tensorflow as tf
    -   # 定义神经网络结构相关的参数。
    -   INPUT_NODE = 784
    -   OUTPUT_NODE = 10
    -   LAYER1_NODE = 500
    -   # 通过tf.get_variable函数来获取变量。在训练神经网络时会创建这些变量;在测试时会通 过保存的模型加载这些变量的取值。而且更加方便的是,因为可以在变量加载时将滑动平均变量
    -   # 重命名,所以可以直接通过同样的名字在训练时使用变量自身,而在测试时使用变量的滑动平 均值。在这个函数中也会将变量的正则化损失加入损失集合。
    -   def get_weight_variable(shape, regularizer):
    -      weights = tf.get_variable(
    -          "weights", shape,
    -           initializer=tf.truncated_normal_initializer(stddev=0.1))
    -      # 当给出了正则化生成函数时,将当前变量的正则化损失加入名字为losses的集合。在这里 使用了add_to_collection函数将一个张量加入一个集合,而这个集合的名称为losses。
    -      # 这是自定义的集合,不在TensorFlow自动管理的集合列表中。
    -      if regularizer != None:
    -           tf.add_to_collection('losses', regularizer(weights))
    -      return weights
    -   # 定义神经网络的前向传播过程。
    -   def inference(input_tensor, regularizer):
    -      # 声明第一层神经网络的变量并完成前向传播过程。
    -      with tf.variable_scope('layer1'):
    -          # 这里通过tf.get_variable或tf.Variable没有本质区别,因为在训练或是测试中 没有在同一个程序中多次调用这个函数。如果在同一个程序中多次调用,在第一次调用
    -          # 之后需要将reuse参数设置为True。
    -         weights = get_weight_variable(
    -              [INPUT_NODE, LAYER1_NODE], regularizer)
    -         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'):
    -          weights = get_weight_variable(
    -                [LAYER1_NODE, OUTPUT_NODE], regularizer)
    -          biases = tf.get_variable(
    -               "biases", [OUTPUT_NODE],
    -               initializer=tf.constant_initializer(0.0))
    -          layer2 = tf.matmul(layer1, weights) + biases
    -      # 返回最后前向传播的结果。
    -      return layer2
    -   # -*- coding: utf-8 -*-
    -   import os
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   # 加载mnist_inference.py中定义的常量和前向传播的函数。
    -   import mnist_inference
    -   # 配置神经网络的参数。
    -   BATCH_SIZE = 100
    -   LEARNING_RATE_BASE = 0.8
    -   LEARNING_RATE_DECAY = 0.99
    -   REGULARAZTION_RATE = 0.0001
    -   TRAINING_STEPS = 30000
    -   MOVING_AVERAGE_DECAY = 0.99
    -   # 模型保存的路径和文件名。
    -   MODEL_SAVE_PATH = "/path/to/model/"
    -   MODEL_NAME = "model.ckpt"
    -   def train(mnist):
    -      # 定义输入输出placeholder。
    -      x = tf.placeholder(
    -           tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')
    -      y_ = tf.placeholder(
    -           tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')
    -      regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    -       # 直接使用mnist_inference.py中定义的前向传播过程。
    -      y = mnist_inference.inference(x, regularizer)
    -      global_step = tf.Variable(0, trainable=False)
    -      # 和5.2.1小节样例中类似地定义损失函数、学习率、滑动平均操作以及训练过程。
    -      variable_averages = tf.train.ExponentialMovingAverage(
    -           MOVING_AVERAGE_DECAY, global_step)
    -      variables_averages_op = variable_averages.apply(
    -           tf.trainable_variables())
    -      cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
    -           y, tf.argmax(y_, 1))
    -      cross_entropy_mean = tf.reduce_mean(cross_entropy)
    -      loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    -      learning_rate = tf.train.exponential_decay(
    -           LEARNING_RATE_BASE,
    -           global_step,
    -           mnist.train.num_examples / BATCH_SIZE,
    -           LEARNING_RATE_DECAY)
    -      train_step = tf.train.GradientDescentOptimizer(learning_rate)\
    -                         .minimize(loss, global_step=global_step)
    -      with tf.control_dependencies([train_step, variables_averages_op]):
    -          train_op = tf.no_op(name='train')
    -      # 初始化TensorFlow持久化类。
    -      saver = tf.train.Saver()
    -      with tf.Session() as sess:
    -          tf.initialize_all_variables().run()
    -          # 在训练过程中不再测试模型在验证数据上的表现,验证和测试的过程将会有一个独 立的程序来完成。
    -          for i in range(TRAINING_STEPS):
    -              xs, ys = mnist.train.next_batch(BATCH_SIZE)
    -              _, loss_value, step = sess.run([train_op, loss, global_step],
    -                                                      feed_dict={x: xs, y_: ys})
    -              # 每1000轮保存一次模型。
    -              if i % 1000 == 0:
    -                     # 输出当前的训练情况。这里只输出了模型在当前训练batch上的损失函 数大小。通过损失函数的大小可以大概了解训练的情况。在验证数据集上的
    -                     # 正确率信息会有一个单独的程序来生成。
    -                     print("After %d training step(s), loss on training "
    -                            "batch is %g." % (step, loss_value))
    -                     # 保存当前的模型。注意这里给出了global_step参数,这样可以让每个被 保存模型的文件名末尾加上训练的轮数,比如“model.ckpt-1000”表示
    -                     # 训练1000轮之后得到的模型。
    -                     saver.save(
    -                          sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME),
    -                          global_step=global_step)
    -   def main(argv=None):
    -      mnist = input_data.read_data_sets("/tmp/data", one_hot=True)
    -      train(mnist)
    -   if __name__ == '__main__':
    -      tf.app.run()
    -   ~/mnist$ python mnist_train.py
    -   Extracting /tmp/data/train-images-idx3-ubyte.gz
    -   Extracting /tmp/data/train-labels-idx1-ubyte.gz
    -   Extracting /tmp/data/t10k-images-idx3-ubyte.gz
    -   Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
    -   After 1 training step(s), loss on training batch is 3.32075.
    -   After 1001 training step(s), loss on training batch is 0.241039.
    -   After 2001 training step(s), loss on training batch is 0.227391.
    -   After 3001 training step(s), loss on training batch is 0.138462.
    -   After 4001 training step(s), loss on training batch is 0.132074.
    -   After 5001 training step(s), loss on training batch is 0.103472.
    -   …
    -   # -*- coding: utf-8 -*-
    -   import time
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   # 加载mnist_inference.py和mnist_train.py中定义的常量和函数。
    -   import mnist_inference
    -   import mnist_train
    -   # 每10秒加载一次最新的模型,并在测试数据上测试最新模型的正确率。
    -   EVAL_INTERVAL_SECS = 10
    -   def evaluate(mnist):
    -      with tf.Graph().as_default() as g:
    -          # 定义输入输出的格式。
    -         x = tf.placeholder(
    -              tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')
    -         y_ = tf.placeholder(
    -              tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')
    -         validate_feed = {x: mnist.validation.images,
    -                               y_:mnist.validation. labels}
    -          # 直接通过调用封装好的函数来计算前向传播的结果。因为测试时不关注正则化损失的值,  所以这里用于计算正则化损失的函数被设置为None。
    -          y = mnist_inference.inference(x, None)
    -           # 使用前向传播的结果计算正确率。如果需要对未知的样例进行分类,那么使用 tf.argmax(y, 1)就可以得到输入样例的预测类别了。
    -          correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    -          accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    -          # 通过变量重命名的方式来加载模型,这样在前向传播的过程中就不需要调用求滑动平均 的函数来获取平均值了。这样就可以完全共用mnist_inference.py中定义的
    -          # 前向传播过程。
    -          variable_averages = tf.train.ExponentialMovingAverage(
    -                mnist_train.MOVING_AVERAGE_DECAY)
    -          variables_to_restore = variable_averages.variables_to_restore()
    -          saver = tf.train.Saver(variables_to_restore)
    -           # 每隔EVAL_INTERVAL_SECS秒调用一次计算正确率的过程以检测训练过程中正确率的# 变化。
    -          while True:
    -              with tf.Session() as sess:
    -                 # tf.train.get_checkpoint_state函数会通过checkpoint文件自动 找到目录中最新模型的文件名。
    -                 ckpt = tf.train.get_checkpoint_state(
    -                     mnist_train.MODEL_SAVE_PATH)
    -                 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('No checkpoint file found')
    -                      return
    -              time.sleep(EVAL_INTERVAL_SECS)
    -   def main(argv=None):
    -      mnist = input_data.read_data_sets("/tmp/data", one_hot=True)
    -      evaluate(mnist)
    -   if __name__ == '__main__':
    -      tf.app.run()
    -   ~/mnist$ python mnist_eval.py
    -   Extracting /tmp/data/train-images-idx3-ubyte.gz
    -   Extracting /tmp/data/train-labels-idx1-ubyte.gz
    -   Extracting /tmp/data/t10k-images-idx3-ubyte.gz
    -   Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
    -   After 1 training step(s), test accuracy = 0.1282
    -   After 1001 training step(s), validation accuracy = 0.9769
    -   After 1001 training step(s), validation accuracy = 0.9769
    -   After 2001 training step(s), validation accuracy = 0.9804
    -   After 3001 training step(s), validation accuracy = 0.982
    -   After 4001 training step(s), validation accuracy = 0.983
    -   After 5001 training step(s), validation accuracy = 0.9829
    -   After 6001 training step(s), validation accuracy = 0.9832
    -   After 6001 training step(s), validation accuracy = 0.9832
    -   …
            - 小结
    - TensorFlow提供了封装好的MNIST数据集处理类,在这里将直接使用这个类。关于如何处理图像数据将在第7章中详细介绍。
    - MNIST数据集中图片的像素矩阵大小为28×28,但为了更清楚地展示,图5-1右侧显示的为14×14矩阵。
    - 因为神经网络模型训练过程中的随机因素,读者不会得到一模一样的结果。
    - 在本小节中,不同神经网络模型使用的参数和5.2.1小节给出的代码中的参数一致。唯一的例外是不使用激活函数的模型使用的学习率为0.05。
    - 因为神经网络的训练过程存在随机因素,本小节中列出的所有结果都是10次运行的平均值。
    - 平均绝对梯度是所有参数梯度绝对值的平均数。
    - 第3章中介绍过张量的名称后面有:0,表示是某个计算节点的第一个输出。而计算节点本身的名称后是没有:0的。
    - 2.1节中有关于Protocol Buffer的具体介绍。
    - 第3章中有更加详细的关于TensorFlow自动维护的集合的介绍。
        -第6章 图像识别与卷积神经网络
            -6.1 图像识别问题简介及经典数据集
            -6.2 卷积神经网络简介
            -6.3 卷积神经网络常用结构
                -6.3.1 卷积层
    -   # 通过tf.get_variable的方式创建过滤器的权重变量和偏置项变量。上面介绍了卷积层 的参数个数只和过滤器的尺寸、深度以及当前层节点矩阵的深度有关,所以这里声明的参数变
    -   # 量是一个四维矩阵,前面两个维度代表了过滤器的尺寸,第三个维度表示当前层的深度,第四 个维度表示过滤器的深度。
    -   filter_weight = tf.get_variable(
    -       'weights', [5, 5, 3, 16],
    -       initializer=tf.truncated_normal_initializer(stddev=0.1))
    -   # 和卷积层的权重类似,当前层矩阵上不同位置的偏置项也是共享的,所以总共有下一层深度个不 同的偏置项。本样例代码中16为过滤器的深度,也是神经网络中下一层节点矩阵的深度。
    -   biases = tf.get_variable(
    -       'biases', [16], initializer=tf.constant_initializer(0.1))
    -   # tf.nn.conv2d提供了一个非常方便的函数来实现卷积层前向传播的算法。这个函数的第一个输 入为当前层的节点矩阵。注意这个矩阵是一个四维矩阵,后面三个维度对应一个节点矩阵,第一
    -   # 维对应一个输入batch。比如在输入层,input[0,:,:,:]表示第一张图片,input[1,:,:,:]  表示第二张图片,以此类推。tf.nn.conv2d第二个参数提供了卷积层的权重,第三个参数为不
    -   # 同维度上的步长。虽然第三个参数提供的是一个长度为4的数组,但是第一维和最后一维的数字 要求一定是1。这是因为卷积层的步长只对矩阵的长和宽有效。最后一个参数是填充(padding)
    -   # 的方法,TensorFlow中提供SAME或是VALID两种选择。其中SAME表示添加全0填充(如 图6-11所示),“VALID”表示不添加(如图6-10所示)。
    -   conv = tf.nn.conv2d(
    -       input, filter_weight, strides=[1, 1, 1, 1], padding='SAME')
    -   # tf.nn.bias_add提供了一个方便的函数给每一个节点加上偏置项。注意这里不能直接使用加 法,因为矩阵上不同位置上的节点都需要加上同样的偏置项。如图6-13所示,虽然下一层神
    -   # 经网络的大小为2×2,但是偏置项只有一个数(因为深度为1),而2×2矩阵中的每一个值都需 要加上这个偏置项。
    -   bias = tf.nn.bias_add(conv, biases)
    -   # 将计算结果通过ReLU激活函数完成去线性化。
    -   actived_conv = tf.nn.relu(bias)
                -6.3.2 池化层
    -   # tf.nn. max_pool实现了最大池化层的前向传播过程,它的参数和tf.nn.conv2d函数类似。 ksize提供了过滤器的尺寸,strides提供了步长信息,padding提供了是否使用全0填充。
    -   pool = tf.nn.max_pool(actived_conv, ksize=[1, 3, 3, 1],
    -                             strides=[1, 2, 2, 1], padding='SAME')
            -6.4 经典卷积网络模型
                -6.4.1 LeNet-5模型
    -   # 调整输入数据placeholder的格式,输入为一个四维矩阵。
    -   x = tf.placeholder(tf.float32, [
    -                 BATCH_SIZE,                           # 第一维表示一个batch中样例的个数。
    -                 mnist_inference.IMAGE_SIZE,   # 第二维和第三维表示图片的尺寸。
    -                 mnist_inference.IMAGE_SIZE,
    -                 mnist_inference.NUM_CHANNELS],        # 第四维表示图片的深度,对于RBG格 式的图片,深度为3。
    -             name='x-input')
    -   …
    -   # 类似地将输入的训练数据格式调整为一个四维矩阵,并将这个调整后的数据传入sess.run过程。
    -   reshaped_xs = np.reshape(xs, (BATCH_SIZE,
    -                                       mnist_inference.IMAGE_SIZE,
    -                                       mnist_inference.IMAGE_SIZE,
    -                                       mnist_inference.NUM_CHANNELS))
    -   # -*- coding: utf-8 -*-
    -   import tensorflow as tf
    -   # 配置神经网络的参数。
    -   INPUT_NODE = 784
    -   OUTPUT_NODE = 10
    -   IMAGE_SIZE = 28
    -   NUM_CHANNELS = 1
    -   NUM_LABELS = 10
    -   # 第一层卷积层的尺寸和深度。
    -   CONV1_DEEP = 32
    -   CONV1_SIZE = 5
    -   # 第二层卷积层的尺寸和深度。
    -   CONV2_DEEP = 64
    -   CONV2_SIZE = 5
    -   # 全连接层的节点个数。
    -   FC_SIZE = 512
    -   # 定义卷积神经网络的前向传播过程。这里添加了一个新的参数train,用于区分训练过程和测试 过程。在这个程序中将用到dropout方法,dropout可以进一步提升模型可靠性并防止过拟合,
    -   # dropout过程只在训练时使用。 [(25)](part0013_split_006.html#ch25)
    -   def inference(input_tensor, train, regularizer):
    -       # 声明第一层卷积层的变量并实现前向传播过程。这个过程和6.3.1小节中介绍的一致。 通过使用不同的命名空间来隔离不同层的变量,这可以让每一层中的变量命名只需要
    -       # 考虑在当前层的作用,而不需要担心重名的问题。和标准LeNet-5模型不大一样,这里 定义的卷积层输入为28×28×1的原始MNIST图片像素。因为卷积层中使用了全0填充,
    -       # 所以输出为28×28×32的矩阵。
    -       with tf.variable_scope('layer1-conv1'):
    -          conv1_weights = tf.get_variable(
    -              "weight",  [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],
    -              initializer=tf.truncated_normal_initializer(stddev=0.1))
    -          conv1_biases = tf.get_variable(
    -              "bias", [CONV1_DEEP], initializer=tf. constant_initializer(0.0))
    -          # 使用边长为5,深度为32的过滤器,过滤器移动的步长为1,且使用全0填充。
    -          conv1 = tf.nn.conv2d(
    -              input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')
    -          relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))
    -      # 实现第二层池化层的前向传播过程。这里选用最大池化层,池化层过滤器的边长为2, 使用全0填充且移动的步长为2。这一层的输入是上一层的输出,也就是28×28×32
    -      # 的矩阵。输出为14×14×32的矩阵。
    -      with tf.name_scope('layer2-pool1'):
    -          pool1 = tf.nn.max_pool(
    -              relu1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    -      # 声明第三层卷积层的变量并实现前向传播过程。这一层的输入为14×14×32的矩阵。 输出为14×14×64的矩阵。
    -      with tf.variable_scope('layer3-conv2'):
    -          conv2_weights = tf.get_variable(
    -              "weight", [CONV2_SIZE, CONV2_SIZE, CONV1_DEEP, CONV2_DEEP],
    -              initializer=tf.truncated_normal_initializer(stddev=0.1))
    -          conv2_biases = tf.get_variable(
    -              "bias", [CONV2_DEEP],
    -              initializer=tf. constant_initializer(0.0))
    -          # 使用边长为5,深度为64的过滤器,过滤器移动的步长为1,且使用全0填充。
    -          conv2 = tf.nn.conv2d(
    -              pool1, conv2_weights, strides=[1, 1, 1, 1], padding='SAME')
    -          relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_biases))
    -      # 实现第四层池化层的前向传播过程。这一层和第二层的结构是一样的。这一层的输入为 14×14×64的矩阵,输出为7×7×64的矩阵。
    -      with tf.name_scope('layer4-pool2'):
    -          pool2 = tf.nn.max_pool(
    -              relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    -      # 将第四层池化层的输出转化为第五层全连接层的输入格式。第四层的输出为7×7×64的矩阵, 然而第五层全连接层需要的输入格式为向量,所以在这里需要将这个7×7×64的矩阵拉直成一
    -      # 个向量。pool2.get_shape函数可以得到第四层输出矩阵的维度而不需要手工计算。注意 因为每一层神经网络的输入输出都为一个batch的矩阵,所以这里得到的维度也包含了一个
    -      # batch中数据的个数。
    -      pool_shape = pool2.get_shape().as_list()
    -      # 计算将矩阵拉直成向量之后的长度,这个长度就是矩阵长宽及深度的乘积。注意这里 pool_shape[0]为一个batch中数据的个数。
    -      nodes = pool_shape[1] * pool_shape[2] * pool_shape[3]
    -      # 通过tf.reshape函数将第四层的输出变成一个batch的向量。
    -      reshaped = tf.reshape(pool2, [pool_shape[0], nodes])
    -      # 声明第五层全连接层的变量并实现前向传播过程。这一层的输入是拉直之后的一组向量, 向量长度为3136,输出是一组长度为512的向量。这一层和之前在第5章中介绍的基本
    -      # 一致,唯一的区别就是引入了dropout的概念。dropout在训练时会随机将部分节点的 输出改为0。dropout可以避免过拟合问题,从而使得模型在测试数据上的效果更好。
    -      # dropout一般只在全连接层而不是卷积层或者池化层使用。
    -      with tf.variable_scope('layer5-fc1'):
    -          fc1_weights = tf.get_variable(
    -              "weight", [nodes, FC_SIZE],
    -               initializer=tf.truncated_normal_initializer(stddev=0.1))
    -          # 只有全连接层的权重需要加入正则化。
    -          if regularizer != None:
    -              tf.add_to_collection('losses', regularizer(fc1_weights))
    -          fc1_biases = tf.get_variable(
    -              "bias", [FC_SIZE], initializer=tf.constant_initializer(0.1))
    -          fc1 = tf.nn.relu(tf.matmul(reshaped, fc1_weights) + fc1_biases)
    -          if train: fc1 = tf.nn.dropout(fc1, 0.5)
    -      # 声明第六层全连接层的变量并实现前向传播过程。这一层的输入为一组长度为512的向量, 输出为一组长度为10的向量。这一层的输出通过Softmax之后就得到了最后的分类结果。
    -      with tf.variable_scope('layer6-fc2'):
    -          fc2_weights = tf.get_variable(
    -              "weight", [FC_SIZE, NUM_LABELS],
    -              initializer=tf.truncated_normal_initializer(stddev=0.1))
    -          if regularizer != None:
    -              tf.add_to_collection('losses', regularizer(fc2_weights))
    -          fc2_biases = tf.get_variable(
    -              "bias", [NUM_LABELS],
    -              initializer=tf. constant_initializer(0.1))
    -         logit = tf.matmul(fc1, fc2_weights) + fc2_biases
    -      # 返回第六层的输出。
    -      return logit
    -   ~/mnist$ python mnist_train.py
    -   Extracting /tmp/data/train-images-idx3-ubyte.gz
    -   Extracting /tmp/data/train-labels-idx1-ubyte.gz
    -   Extracting /tmp/data/t10k-images-idx3-ubyte.gz
    -   Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
    -   After 1 training step(s), loss on training batch is 6.45373.
    -   After 1001 training step(s), loss on training batch is 0.824825.
    -   After 2001 training step(s), loss on training batch is 0.646993.
    -   After 3001 training step(s), loss on training batch is 0.759975.
    -   After 4001 training step(s), loss on training batch is 0.68468.
    -   After 5001 training step(s), loss on training batch is 0.630368.
    -   …
                -6.4.2 Inception-v3模型
    -   # 直接使用TensorFlow原始API实现卷积层。
    -   with tf.variable_scope(scope_name):
    -       weights = tf.get_variable("weight", …)
    -       biases = tf.get_variable("bias", …)
    -       conv = tf.nn.conv2d(…)
    -   relu = tf.nn.relu(tf.nn.bias_add(conv, biases))
    -   # 使用TensorFlow-Slim实现卷积层。通过TensorFlow-Slim可以在一行中实现一个卷积层 的前向传播算法。slim.conv2d函数的有3个参数是必填的。第一个参数为输入节点矩阵,第
    -   # 二参数是当前卷积层过滤器的深度,第三个参数是过滤器的尺寸。可选的参数有过滤器移动的步 长、是否使用全0填充、激活函数的选择以及变量的命名空间等。
    -   net = slim.conv2d(input, 32, [3, 3])
    -   # slim.arg_scope函数可以用于设置默认的参数取值。slim.arg_scope函数的第一个参数是 一个函数列表,在这个列表中的函数将使用默认的参数取值。比如通过下面的定义, 调用
    -   # slim.conv2d(net, 320, [1, 1])函数时会自动加上stride=1和padding='SAME'的参 数。如果在函数调用时指定了stride,那么这里设置的默认值就不会再使用。通过这种方式
    -   # 可以进一步减少冗余的代码。
    -   with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
    -                             stride=1 , padding='SAME'):
    -       …
    -       # 此处省略了Inception-v3模型中其他的网络结构而直接实现最后面红色方框中的。 Inception结构。假设输入图片经过之前的神经网络前向传播的结果保存在变量net
    -       # 中。
    -       net = 上一层的输出节点矩阵
    -       # 为一个Inception模块声明一个统一的变量命名空间。
    -       with tf.variable_scope('Mixed_7c'):
    -           # 给Inception模块中每一条路径声明一个命名空间。
    -           with tf.variable_scope('Branch_0'):
    -               # 实现一个过滤器边长为1,深度为320的卷积层。
    -               branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1')
    -           # Inception模块中第二条路径。这条计算路径上的结构本身也是一个Inception结 构。
    -           with tf.variable_scope('Branch_1'):
    -               branch_1 = slim.conv2d(net, 384, [1, 1], scope='Conv2d_0a_1x1')
    -               # tf.concat函数可以将多个矩阵拼接起来。tf.concat函数的第一个参数指定 了拼接的维度,这里给出的“3”代表了矩阵是在深度这个维度上进行拼接。图6-16
    -               # 中展示了在深度上拼接矩阵的方式。
    -               branch_1 = tf.concat(3, [
    -                   # 如图6-17所示,此处2层卷积层的输入都是branch_1而不是net。
    -                   slim.conv2d(branch_1, 384, [1, 3], scope='Conv2d_0b_1x3'),
    -                   slim.conv2d(branch_1, 384, [3, 1], scope='Conv2d_0c_3x1')])
    -           # Inception模块中第三条路径。此计算路径也是一个Inception结构。
    -           with tf.variable_scope('Branch_2'):
    -                branch_2 = slim.conv2d(
    -                    net, 448, [1, 1], scope='Conv2d_0a_1x1')
    -                branch_2 = slim.conv2d(
    -                    branch_2, 384, [3, 3], scope='Conv2d_ 0b_3x3')
    -                branch_2 = tf.concat(3, [
    -                    slim.conv2d(branch_2, 384,
    -                                  [1, 3], scope='Conv2d_0c_1x3'),
    -                    slim.conv2d(branch_2, 384,
    -                                  [3, 1], scope='Conv2d_0d_3x1')])
    -           # Inception模块中第四条路径。
    -           with tf.variable_scope('Branch_3'):
    -               branch_3 = slim.avg_pool2d(
    -                   net, [3, 3], scope='AvgPool_0a_3x3')
    -               branch_3 = slim.conv2d(
    -                   branch_3, 192, [1, 1], scope='Conv2d_ 0b_1x1')
    -           # 当前Inception模块的最后输出是由上面四个计算结果拼接得到的。
    -           net = tf.concat(3, [branch_0, branch_1, branch_2, branch_3])
            -6.5 卷积神经网络迁移学习
                -6.5.1 迁移学习介绍
                -6.5.2 TensorFlow实现迁移学习
    -   curl http://download.tensorflow.org/example_images/flower_photos.tgz
    -   tar xzf flower_photos.tgz
    -   wget https://storage.googleapis.com/download.tensorflow.org/models/\
    -   inception_dec_2015.zip
    -   unzip tensorflow/examples/label_image/data/inception_dec_2015.zip
    -   # -*- coding: utf-8 -*-
    -   import glob
    -   import os.path
    -   import random
    -   import numpy as np
    -   import tensorflow as tf
    -   from tensorflow.python.platform import gfile
    -   # Inception-v3模型瓶颈层的节点个数。
    -   BOTTLENECK_TENSOR_SIZE = 2048
    -   # Inception-v3模型中代表瓶颈层结果的张量名称。在谷歌提供的Inception-v3模型中,这 个张量名称就是'pool_3/_reshape:0'。在训练的模型时,可以通过tensor.name来获取张
    -   # 量的名称。
    -   BOTTLENECK_TENSOR_NAME = 'pool_3/_reshape:0'
    -   # 图像输入张量所对应的名称。
    -   JPEG_DATA_TENSOR_NAME = 'DecodeJpeg/contents:0'
    -   # 下载的谷歌训练好的Inception-v3模型文件目录。
    -   MODEL_DIR = '/path/to/model'
    -   # 下载的谷歌训练好的Inception-v3模型文件名。
    -   MODEL_FILE = 'classify_image_graph_def.pb'
    -   # 因为一个训练数据会被使用多次,所以可以将原始图像通过Inception-v3模型计算得到 的特征向量保存在文件中,免去重复的计算。下面的变量定义了这些文件的存放地址。
    -   CACHE_DIR = '/tmp/bottleneck'
    -   # 图片数据文件夹。在这个文件夹中每一个子文件夹代表一个需要区分的类别,每个子文件夹中 存放了对应类别的图片。
    -   INPUT_DATA = '/path/to/flower_data'
    -   # 验证的数据百分比。
    -   VALIDATION_PERCENTAGE = 10
    -   # 测试的数据百分比。
    -   TEST_PERCENTAGE = 10
    -   # 定义神经网络的设置。
    -   LEARNING_RATE = 0.01
    -   STEPS = 4000
    -   BATCH = 100
    -   # 这个函数从数据文件夹中读取所有的图片列表并按训练、验证、测试数据分开。 testing_percentage和validation_percentage参数指定了测试数据集和验证数据集的
    -   # 大小。
    -   def create_image_lists(testing_percentage, validation_percentage):
    -      # 得到的所有图片都存在result这个字典(dictionary)里。这个字典的key为类别的名 称,value是也是一个字典,字典里存储了所有的图片名称。
    -      result = {}
    -      # 获取当前目录下所有的子目录。
    -      sub_dirs = [x[0] for x in os.walk(INPUT_DATA)]
    -      # 得到的第一个目录是当前目录,不需要考虑。
    -      is_root_dir = True
    -      for sub_dir in sub_dirs:
    -      if is_root_dir:
    -          is_root_dir = False
    -          continue
    -      # 获取当前目录下所有的有效图片文件。
    -      extensions = ['jpg', 'jpeg', 'JPG', 'JPEG']
    -      file_list = []
    -      dir_name = os.path.basename(sub_dir)
    -      for extension in extensions:
    -          file_glob = os.path.join(INPUT_DATA, dir_name, '*.' + extension)
    -          file_list.extend(glob.glob(file_glob))
    -      if not file_list: continue
    -      # 通过目录名获取类别的名称。
    -      label_name = dir_name.lower()
    -      # 初始化当前类别的训练数据集、测试数据集和验证数据集。
    -      training_images = []
    -      testing_images = []
    -      validation_images = []
    -      for file_name in file_list:
    -          base_name = os.path.basename(file_name)
    -          # 随机将数据分到训练数据集、测试数据集和验证数据集。
    -          chance = np.random.randint(100)
    -          if chance < validation_percentage:
    -              validation_images.append(base_name)
    -          elif chance < (testing_percentage + validation_percentage):
    -              testing_images.append(base_name)
    -          else:
    -              training_images.append(base_name)
    -      # 将当前类别的数据放入结果字典。
    -      result[label_name] = {
    -          'dir': dir_name,
    -          'training': training_images,
    -          'testing': testing_images,
    -          'validation': validation_images,
    -      }
    -      # 返回整理好的所有数据。
    -      return result
    -   # 这个函数通过类别名称、所属数据集和图片编号获取一张图片的地址。 image_lists参数给出了所有图片信息。
    -   # image_dir参数给出了根目录。存放图片数据的根目录和存放图片特征向量的根目录地址不同。 label_name参数给定了类别的名称。
    -   # index参数给定了需要获取的图片的编号。 category参数指定了需要获取的图片是在训练数据集、测试数据集还是验证数据集。
    -   def get_image_path(image_lists, image_dir, label_name, index, category):
    -      # 获取给定类别中所有图片的信息。
    -      label_lists = image_lists[label_name]
    -      # 根据所属数据集的名称获取集合中的全部图片信息。
    -      category_list = label_lists[category]
    -      mod_index = index % len(category_list)
    -      # 获取图片的文件名。
    -      base_name = category_list[mod_index]
    -      sub_dir = label_lists['dir']
    -      # 最终的地址为数据根目录的地址加上类别的文件夹加上图片的名称。
    -      full_path = os.path.join(image_dir, sub_dir, base_name)
    -      return full_path
    -   # 这个函数通过类别名称、所属数据集和图片编号获取经过Inception-v3模型处理之后的特征向量 文件地址。
    -   def get_bottleneck_path(image_lists, label_name, index, category):
    -      return get_image_path(image_lists, CACHE_DIR,
    -                             label_name, index, category) + '.txt'
    -   # 这个函数使用加载的训练好的Inception-v3模型处理一张图片,得到这个图片的特征向量。
    -   def run_bottleneck_on_image(sess, image_data, image_data_tensor,
    -                                   bottleneck_ tensor):
    -      # 这个过程实际上就是将当前图片作为输入计算瓶颈张量的值。这个瓶颈张量的值就是这 张图片的新的特征向量。
    -      bottleneck_values = sess.run(bottleneck_tensor,
    -                                     {image_data_tensor: image_data})
    -      # 经过卷积神经网络处理的结果是一个四维数组,需要将这个结果压缩成一个特征 向量(一维数组)。
    -      bottleneck_values = np.squeeze(bottleneck_values)
    -      return bottleneck_values
    -   # 这个函数获取一张图片经过Inception-v3模型处理之后的特征向量。这个函数会先试图寻找 已经计算且保存下来的特征向量,如果找不到则先计算这个特征向量,然后保存到文件。
    -   def get_or_create_bottleneck(
    -       sess, image_lists, label_name, index,
    -       category, jpeg_data_tensor, bottleneck_tensor):
    -      # 获取一张图片对应的特征向量文件的路径。
    -      label_lists = image_lists[label_name]
    -      sub_dir = label_lists['dir']
    -      sub_dir_path = os.path.join(CACHE_DIR, sub_dir)
    -      if not os.path.exists(sub_dir_path): os.makedirs(sub_dir_path)
    -      bottleneck_path = get_bottleneck_path(
    -      image_lists, label_name, index, category)
    -      # 如果这个特征向量文件不存在,则通过Inception-v3模型来计算特征向量,并将计算的结果 存入文件。
    -      if not os.path.exists(bottleneck_path):
    -      # 获取原始的图片路径。
    -      image_path = get_image_path(
    -           image_lists, INPUT_DATA, label_name, index, category)
    -      # 获取图片内容。
    -      image_data = gfile.FastGFile(image_path, 'rb').read()
    -      # 通过Inception-v3模型计算特征向量。
    -      bottleneck_values = run_bottleneck_on_image(
    -           sess, image_data, jpeg_data_tensor, bottleneck_tensor)
    -      # 将计算得到的特征向量存入文件。
    -      bottleneck_string = ','.join(str(x) for x in bottleneck_values)
    -      with open(bottleneck_path, 'w') as bottleneck_file:
    -          bottleneck_file.write(bottleneck_string)
    -      else:
    -      # 直接从文件中获取图片相应的特征向量。
    -      with open(bottleneck_path, 'r') as bottleneck_file:
    -          bottleneck_string = bottleneck_file.read()
    -      bottleneck_values = [float(x) for x in bottleneck_string.split(',')]
    -      # 返回得到的特征向量。
    -      return bottleneck_values
    -   # 这个函数随机获取一个batch的图片作为训练数据。
    -   def get_random_cached_bottlenecks(
    -       sess, n_classes, image_lists, how_many, category,
    -       jpeg_data_tensor, bottleneck_tensor):
    -      bottlenecks = []
    -      ground_truths = []
    -      for _ in range(how_many):
    -      # 随机一个类别和图片的编号加入当前的训练数据。
    -      label_index = random.randrange(n_classes)
    -      label_name = list(image_lists.keys())[label_index]
    -      image_index = random.randrange(65536)
    -      bottleneck = get_or_create_bottleneck(
    -          sess, image_lists, label_name, image_index, category,
    -            jpeg_data_tensor, bottleneck_tensor)
    -      ground_truth = np.zeros(n_classes, dtype=np.float32)
    -      ground_truth[label_index] = 1.0
    -      bottlenecks.append(bottleneck)
    -      ground_truths.append(ground_truth)
    -      return bottlenecks, ground_truths
    -   # 这个函数获取全部的测试数据。在最终测试的时候需要在所有的测试数据上计算正确率。
    -   def get_test_bottlenecks(sess, image_lists, n_classes,
    -                             jpeg_data_tensor, bottleneck_tensor):
    -      bottlenecks = []
    -      ground_truths = []
    -      label_name_list = list(image_lists.keys())
    -      # 枚举所有的类别和每个类别中的测试图片。
    -      for label_index, label_name in enumerate(label_name_list):
    -      category = 'testing'
    -      for index, unused_base_name in enumerate(
    -                image_lists[label_name][category]):
    -          # 通过Inception-v3模型计算图片对应的特征向量,并将其加入最终数据的列表。
    -          bottleneck = get_or_create_bottleneck(
    -                sess, image_lists, label_name, index, category,
    -                jpeg_data_tensor, bottleneck_tensor)
    -          ground_truth = np.zeros(n_classes, dtype=np.float32)
    -          ground_truth[label_index] = 1.0
    -          bottlenecks.append(bottleneck)
    -          ground_truths.append(ground_truth)
    -      return bottlenecks, ground_truths
    -   def main(_):
    -      # 读取所有图片。
    -      image_lists = create_image_lists(TEST_PERCENTAGE, VALIDATION_PERCENTAGE)
    -      n_classes = len(image_lists.keys())
    -      # 读取已经训练好的Inception-v3模型。谷歌训练好的模型保存在了GraphDef Protocol  Buffer中,里面保存了每一个节点取值的计算方法以及变量的取值。TensorFlow模型持
    -      # 久化的问题在第5章中有详细的介绍。
    -      with gfile.FastGFile(os.path.join(MODEL_DIR, MODEL_FILE), 'rb') as f:
    -      graph_def = tf.GraphDef()
    -      graph_def.ParseFromString(f.read())
    -      # 加载读取的Inception-v3模型,并返回数据输入所对应的张量以及计算瓶颈层结果所对应 的张量。
    -      bottleneck_tensor, jpeg_data_tensor = tf.import_graph_def(
    -      graph_def,
    -       return_elements=[BOTTLENECK_TENSOR_NAME, JPEG_DATA_TENSOR_NAME])
    -      # 定义新的神经网络输入,这个输入就是新的图片经过Inception-v3模型前向传播到达瓶颈层 是的节点取值。可以将这个过程类似的理解为一种特征提取。
    -      bottleneck_input = tf.placeholder(
    -       tf.float32, [None, BOTTLENECK_TENSOR_SIZE],
    -       name='BottleneckInputPlaceholder')
    -      # 定义新的标准答案输入。
    -      ground_truth_input = tf.placeholder(
    -       tf.float32, [None, n_classes], name='GroundTruthInput')
    -      # 定义一层全链接层来解决新的图片分类问题。因为训练好的Inception-v3模型已经将原始 的图片抽象为了更加容易分类的特征向量了,所以不需要再训练那么复杂的神经网络来完成
    -      # 这个新的分类任务。
    -      with tf.name_scope('final_training_ops'):
    -      weights = tf.Variable(tf.truncated_normal(
    -           [BOTTLENECK_TENSOR_SIZE, n_classes], stddev=0.001))
    -      biases = tf.Variable(tf.zeros([n_classes]))
    -      logits = tf.matmul(bottleneck_input, weights) + biases
    -      final_tensor = tf.nn.softmax(logits)
    -      # 定义交叉熵损失函数。
    -      cross_entropy = tf.nn.softmax_cross_entropy_with_logits(
    -       logits,ground_truth_input)
    -      cross_entropy_mean = tf.reduce_mean(cross_entropy)
    -      train_step = tf.train.GradientDescentOptimizer(LEARNING_RATE)\
    -                     .minimize(cross_entropy_mean)
    -      # 计算正确率。
    -      with tf.name_scope('evaluation'):
    -      correct_prediction = tf.equal(tf.argmax(final_tensor, 1),
    -                               tf.argmax(ground_truth_input, 1))
    -      evaluation_step = tf.reduce_mean(
    -            tf.cast(correct_prediction,tf.float32))
    -      with tf.Session() as sess:
    -      init = tf.initialize_all_variables()
    -      sess.run(init)
    -      # 训练过程。
    -      for i in range(STEPS):
    -          # 每次获取一个batch的训练数据。
    -          train_bottlenecks, train_ground_truth = \
    -                get_random_cached_bottlenecks(
    -                 sess, n_classes, image_lists, BATCH,
    -                    'training', jpeg_data_tensor, bottleneck_tensor)
    -          sess.run(train_step,
    -                       feed_dict={bottleneck_input: train_bottlenecks,
    -                                    ground_truth_input: train_ground_truth})
    -          # 在验证数据上测试正确率。
    -          if i % 100 == 0 or i + 1 == STEPS:
    -              validation_bottlenecks, validation_ground_truth = \
    -                     get_random_cached_bottlenecks(
    -                     sess, n_classes, image_lists, BATCH,
    -                         'validation', jpeg_data_tensor, bottleneck_tensor)
    -              validation_accuracy = sess.run(
    -                      evaluation_step, feed_dict={
    -                     bottleneck_input: validation_bottlenecks,
    -                         ground_truth_ input: validation_ground_truth})
    -              print('Step %d: Validation accuracy on random sampled '
    -                        '%d examples = %.1f%%' %
    -                        (i, BATCH, validation_accuracy * 100))
    -          # 在最后的测试数据上测试正确率。
    -          test_bottlenecks, test_ground_truth = get_test_bottlenecks(
    -                sess, image_lists, n_classes, jpeg_data_tensor,
    -                bottleneck_tensor)
    -          test_accuracy = sess.run(evaluation_step, feed_dict={
    -                bottleneck_input: test_bottlenecks,
    -                ground_truth_input: test_ground_truth})
    -          print('Final test accuracy = %.1f%%' % (test_accuracy * 100))
    -   if __name__ == '__main__':
    -   tf.app.run()
    -   Step 0: Validation accuracy on random sampled 100 examples = 44.0%
    -   Step 200: Validation accuracy on random sampled 100 examples = 79.0%
    -   Step 400: Validation accuracy on random sampled 100 examples = 85.0%
    -   Step 600: Validation accuracy on random sampled 100 examples = 92.0%
    -   Step 800: Validation accuracy on random sampled 100 examples = 87.0%
    -   Step 1000: Validation accuracy on random sampled 100 examples = 93.0%
    -   ...
    -   Step 3999: Validation accuracy on random sampled 100 examples = 94.0%
    -   Final test accuracy = 93.6%
            - 小结
    - 详情请参考论文:Learning Semantic Representations Using Convolutional Neural Networks for Web Search、A Deep Architecture for Semantic Parsing、A Convolutional Neural Network for Modelling Sentences及Convolutional Neural Networks for Sentence Classification
    -。
    - 参见:Wallach I, Dzamba M, Heifets A. AtomNet: A Deep Convolutional Neural Network for Bioactivity Prediction in Structure-based Drug Discovery
    -[J]. Mathematische Zeitschrift, 2015.
    - 参见:Liu Y, Racah E, Prabhat, et al. Application of Deep Convolutional Neural Networks for Detecting Extreme Weather in Climate Datasets
    -[J]. 2016.
    - 参见:Clark C, Storkey A. Teaching Deep Convolutional Neural Networks to Play Go
    -[J]. Eprint Arxiv, 2015.
    - 数字来源于http://yann.lecun.com/exdb/mnist。
    - 人工标注错误率参见: Simard P, Lecun Y, Denker J S. Efficient Pattern Recognition Using a New Transformation Distance
    -[M]// Advances in Neural Information Processing Systems (NIPS 1992). 1993.
    - 更多关于图像词典项目的介绍可以参考其官方网站http://groups.csail.mit.edu/vision/TinyImages。
    - MNIST数据集中每一张图片只包含一个数字;Cifar-10和Cifar-100数据集中每一张图片只包含一个种类的物体。
    - 人工标注的准确率来自技术博客http://torch.ch/blog/2015/07/30/cifar.html。
    - 具体数字出自: Springenberg J T, Dosovitskiy A, Brox T, et al. Striving for Simplicity: The All Convolutional Net
    -[J]. Eprint Arxiv, 2014.
    - WordNet是一个大型英语语义网,里面将名词、动词、形容词和副词整理成了同义词集,并标注了不同同义词集之间的关系。WordNet具体信息可以参考WordNet官网:https://wordnet.princeton.edu/。
    - ImageNet中图片的具体整理和标注方式可以参考:Deng J, Dong W, Socher R, et al. ImageNet: A large-scale hierarchical image database
    -[C]// Computer Vision and Pattern Recognition, 2009\. CVPR 2009\. IEEE Conference on. IEEE, 2009.
    - 此图片来自于ImageNet官方网站。
    - 第8章将介绍循环神经网络。
    - 在第4章的图4-5中介绍了神经元的结构。
    - 在RGB色彩模式下,一幅完整的图像是由红色、绿色和蓝色3个通道组成的。因为每个通道在每个像素点上都有亮度值,所以整个图片就可以表示成一个三维矩阵。
    - 此图片来自斯坦福大学在线卷积神经网络教程http://cs231n.github.io/convolutional-networks/。
    - 此处全0填充的方式和TensorFlow中实现的方式略有不同,但是原理是一样的。
    - 池化层主要用于减小矩阵的长和宽。虽然池化层也可以减小矩阵深度,但是实践中一般不会这样使用。
    - 有研究指出池化层对模型效果的影响不大,具体细节可以参考:Springenberg J T, Dosovitskiy A, Brox T, et al. Striving for Simplicity: The All Convolutional Net
    -[J]. Eprint Arxiv, 2014.不过目前主流的卷积神经网络模型中都含有池化层。
    - Lecun Y, Bottou L, Bengio Y, et al. Gradient-based learning applied to document recognition
    -[J]. Proceedings of the IEEE, 1998.
    - 此图片来自论文Gradient-based learning applied to document recognition
    -。
    - 论文GradientBased Learning Applied to Document Recognition
    -提出的LeNet-5模型中,卷积层和池化层的实现与6.3节中介绍的TensorFlow的实现有细微的区别,本书不过多的讨论具体细节,而是着重介绍模型的整体框架。
    - LeNet-5模型论文中最后一层输出层的结构和全连接层有区别,但我们这用全连接层近似的表示。
    - 关于dropout的详情可以参考论文Hinton G E, Srivastava N, Krizhevsky A, et al. Improving neural networks by preventing co-adaptation of feature detectors
    -[J]. Computer Science, 2012.
    - 具体可以参考论文Striving for Simplicity: The All Convolutional Net
    -。
    - Simonyan K, Zisserman A. Very Deep Convolutional Networks for Large-Scale Image Recognition
    -[J]. Computer Science, 2014.
    - 此表源自论文Very Deep Convolutional Networks for Large-Scale Image Recognition
    -。
    - Szegedy C, Vanhoucke V, Ioffe S, et al. Rethinking the Inception Architecture for Computer Vision[J]. Computer Science, 2015.
    - 在TensorFlow的GitHub代码库上找到完整的Inception-v3模型的源码。GitHub的地址为https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/slim/python/slim/nets/inception_v3.py。
    - 在这里层数只计算了卷积层和全连接层的个数,没有参数的池化层没有包括在内。
    - Donahue J, Jia Y, Vinyals O, et al. DeCAF: A Deep Convolutional Activation Feature for Generic Visual Recognition
    -[J]. Computer Science, 2013.
    - 第10章将介绍TensorFlow如何使用GPU加速训练过程。
    - 数据下载和数据预处理的时间没有计算在内。
        -第7章 图像数据处理
            -7.1 TFRecord输入数据格式
                -7.1.1 TFRecord格式介绍
    -   message Example {
    -     Features features = 1;
    -   };
    -   message Features {
    -     map feature = 1;
    -   };
    -   message Feature {
    -     oneof kind {
    -   BytesList bytes_list = 1;
    -   FloatList float_list = 2;
    -   Int64List int64_list = 3;
    -     }
    -   };
                -7.1.2 TFRecord样例程序
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   import numpy as np
    -   # 生成整数型的属性。
    -   def _int64_feature(value):
    -   return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
    -   # 生成字符串型的属性。
    -   def _bytes_feature(value):
    -   return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
    -   mnist = input_data.read_data_sets(
    -   "/path/to/mnist/data", dtype=tf.uint8, one_hot=True)
    -   images = mnist.train.images
    -   # 训练数据所对应的正确答案,可以作为一个属性保存在TFRecord中。
    -   labels = mnist.train.labels
    -   # 训练数据的图像分辨率,这可以作为Example中的一个属性。
    -   pixels = images.shape[1]
    -   num_examples = mnist.train.num_examples
    -   # 输出TFRecord文件的地址。
    -   filename = "/path/to/output.tfrecords"
    -   # 创建一个writer来写TFRecord文件。
    -   writer = tf.python_io.TFRecordWriter(filename)
    -   for index in range(num_examples):
    -   # 将图像矩阵转化成一个字符串。
    -   image_raw = images[index].tostring()
    -   # 将一个样例转化为Example Protocol Buffer,并将所有的信息写入这个数据结构。
    -   example = tf.train.Example(features=tf.train.Features(feature={
    -       'pixels': _int64_feature(pixels),
    -       'label': _int64_feature(np.argmax(labels[index])),
    -       'image_raw': _bytes_feature(image_raw)}))
    -   # 将一个Example写入TFRecord文件。
    -   writer.write(example.SerializeToString())
    -   writer.close()
    -   import tensorflow as tf
    -   # 创建一个reader来读取TFRecord文件中的样例。
    -   reader = tf.TFRecordReader()
    -   # 创建一个队列来维护输入文件列表,在7.3.2小节中将更加详细的介绍 tf.train.string_input_producer函数。
    -   filename_queue = tf.train.string_input_producer(
    -   ["/path/to/output.tfrecords"])
    -   # 从文件中读出一个样例。也可以使用read_up_to函数一次性读取多个样例。
    -   _, serialized_example = reader.read(filename_queue)
    -   # 解析读入的一个样例。如果需要解析多个样例,可以用parse_example函数。
    -   features = tf.parse_single_example(
    -     serialized_example,
    -     features={
    -         # TensorFlow提供两种不同的属性解析方法。一种是方法是tf.FixedLenFeature,  这种方法解析的结果为一个Tensor。另一种方法是tf.VarLenFeature,这种方法
    -         # 得到的解析结果为SparseTensor,用于处理稀疏数据。这里解析数据的格式需要和 上面程序写入数据的格式一致。
    -         'image_raw': tf.FixedLenFeature([], tf.string),
    -         'pixels': tf.FixedLenFeature([], tf.int64),
    -         'label': tf.FixedLenFeature([], tf.int64),
    -     })
    -   # tf.decode_raw可以将字符串解析成图像对应的像素数组。
    -   images = tf.decode_raw(features['image_raw'], tf.uint8)
    -   labels = tf.cast(features['label'], tf.int32)
    -   pixels = tf.cast(features['pixels'], tf.int32)
    -   sess = tf.Session()
    -   # 启动多线程处理输入数据,7.3节将更加详细地介绍TensorFlow多线程处理。
    -   coord = tf.train.Coordinator()
    -   threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    -   # 每次运行可以读取TFRecord文件中的一个样例。当所有样例都读完之后,在此样例中程序 会在重头读取。
    -   for i in range(10):
    -   image, label, pixel = sess.run([images, labels, pixels])
            -7.2 图像数据处理
                -7.2.1 TensorFlow图像处理函数
    -   # matplotlib.pyplot是一个python的画图工具 [(1)](part0014_split_004.html#2CK-6c6a83a4f5d442b18ece5cfab416f8bb)
    -   # 化经过TensorFlow处理的图像。
    -   import matplotlib.pyplot as plt
    -   import tensorflow as tf
    -   # 读取图像的原始数据。
    -   image_raw_data = tf.gfile.FastGFile("/path/to/picture", 'r').read()
    -   with tf.Session() as sess:
    -      # 将图像使用jpeg的格式解码从而得到图像对应的三维矩阵。TensorFlow还提供了 tf.image.decode_png函数对png格式的图像进行解码。解码之后的结果为一个
    -      # 张量,在使用它的取值之前需要明确调用运行的过程。
    -      img_data = tf.image.decode_jpeg(image_raw_data)
    -      print img_data.eval()
    -      # 输出解码之后的三维矩阵,上面这一行将输出下面的内容。
    -      '''
    -      [[[165 160 138]
    -    ...,
    -    [105 140  50]]
    -      [[166 161 139]
    -   ...,
    -   [106 139  48]]
    -   ...,
    -   [[207 200 181]
    -    ...,
    -    [106  81  50]]]
    -     '''
    -      # 使用pyplot工具可视化得到的图像。可以得到图7-1中展示了的图像。
    -      plt.imshow(img_data.eval())
    -      plt.show()
    -      # 将数据的类型转化成实数方便下面的样例程序对图像进行处理。
    -      img_data = tf.image.convert_image_dtype(img_data, dtype=tf.float32)
    -      # 将表示一张图像的三维矩阵重新按照jpeg格式编码并存入文件中。打开这张图像, 可以得到和原始图像一样的图像。
    -      encoded_image = tf.image.encode_jpeg(img_data)
    -      with tf.gfile.GFile("/path/to/output", "wb") as f:
    -      f.write(encoded_image.eval())
    -      # 加载原始图像,定义会话等过程和图像编码处理中代码一致,在下面的样例中就全部略去了, 假设img_data是已经解码且进行过类型转化的图像。
    -      ...
    -      # 通过tf.image.resize_images函数调整图像的大小。这个函数第一个参数为原始图像, 第二个和第三个参数为调整后图像的大小,method参数给出了调整图像大小的算法。
    -      resized = tf.image.resize_images(img_data, [300, 300], method=0)
    -      # 输出调整后图像的大小,此处的结果为(300, 300, ?)。表示图像的大小是300×300, 但图像的深度在没有明确设置之前会是问号。
    -      print img_data.get_shape()
    -      # 通过pyplot可视化的过程和图像编码处理中给出的代码一致,在以下代码中也将略去。
    -   # 通过tf.image.resize_image_with_crop_or_pad函数调整图像的大小。这个函数的 第一个参数为原始图像,后面两个参数是调整后的目标图像大小。如果原始图像的尺寸大于目标
    -   # 图像,那么这个函数会自动截取原始图像中居中的部分(如图7-3(b)所示)。如果目标图像 大于原始图像,这个函数会自动在原始图像的四周填充全0背景(如图7-3(c)所示)。因为原
    -   # 始图像的大小为1797×2673,所以下面的第一个命令会自动剪裁,而第二个命令会自动填充。
    -   croped = tf.image.resize_image_with_crop_or_pad(img_data, 1000, 1000)
    -   padded = tf.image.resize_image_with_crop_or_pad(img_data, 3000, 3000)
    -   # 通过tf.image. central_crop函数可以按比例裁剪图像。这个函数的第一个参数为原始图 像,第二个为调整比例,这个比例需要是一个(0,1]的实数。图7-4(b)中显示了调整之
    -   # 后的图像。
    -   central_cropped = tf.image.central_crop(img_data, 0.5)
    -   # 将图像上下翻转,翻转后的效果见图7-5(b)。
    -   flipped = tf.image.flip_up_down(img_data)
    -   # 将图像左右翻转,翻转后的效果见图7-5(c)。
    -   flipped = tf.image.flip_left_right(img_data)
    -   # 将图像沿对角线翻转,翻转后的效果见图7-5(d)。
    -   transposed = tf.image.transpose_image(img_data)
    -   # 以一定概率上下翻转图像。
    -   flipped = tf.image.random_flip_up_down(img_data)
    -   # 以一定概率左右翻转图像。
    -   flipped = tf.image.random_flip_left_right(img_data)
    -   # 将图像的亮度-0.5,得到的图像效果如图7-6(b)所示。
    -   adjusted = tf.image.adjust_brightness(img_data, -0.5)
    -   # 将图像的亮度+0.5,得到的图像效果如图7-6(c)所示。
    -   adjusted = tf.image.adjust_brightness(img_data, 0.5)
    -   # 在[-max_delta, max_delta)的范围随机调整图像的亮度。
    -   adjusted = tf.image.random_brightness(image, max_delta)
    -   # 将图像的对比度-5,得到的图像效果如图7-7(b)所示。
    -   adjusted = tf.image.adjust_contrast(img_data, -5)
    -   # 将图像的对比度+5,得到的图像效果如图7-7(c)所示。
    -   adjusted = tf.image.adjust_contrast(img_data, 5)
    -   # 在[lower, upper]的范围随机调整图的对比度。
    -   adjusted = tf.image.random_contrast(image, lower, upper)
    -   # 下面四条命令分别将色相加0.1、0.3、0.6和0.9,得到的效果分别在 图7-8(b),(c), (d),(e)中展示。
    -   adjusted = tf.image.adjust_hue(img_data, 0.1)
    -   adjusted = tf.image.adjust_hue(img_data, 0.3)
    -   adjusted = tf.image.adjust_hue(img_data, 0.6)
    -   adjusted = tf.image.adjust_hue(img_data, 0.9)
    -   # 在[-max_delta, max_delta]的范围随机调整图像的色相。 max_delta的取值在[0, 0.5]之间。
    -   adjusted = tf.image.random_hue(image, max_delta)
    -   # 将图像的饱和度-5,得到的图像效果如图7-9(b)所示。
    -   adjusted = tf.image.adjust_saturation(img_data, -5)
    -   # 将图像的饱和度+5,得到的图像效果如图7-9(c)所示。
    -   adjusted = tf.image.adjust_saturation(img_data, 5)
    -   # 在[lower, upper]的范围随机调整图的饱和度。
    -   adjusted = tf.image.random_saturation(image, lower, upper)
    -   # 将代表一张图像的三维矩阵中的数字均值变为0,方差变为1。调整后的图像如图7-10(b)。
    -   adjusted = tf.image.per_image_whitening(img_data)
    -      # 将图像缩小一些,这样可视化能让标注框更加清楚。
    -      img_data = tf.image.resize_images(img_data, 180, 267, method=1)
    -      # tf.image.draw_bounding_boxes函数要求图像矩阵中的数字为实数,所以需要先将 图像矩阵转化为实数类型。tf.image.draw_bounding_boxes函数图像的输入是一个
    -      # bacth的数据,也就是多张图像组成的四维矩阵,所以需要将解码之后的图像矩阵加一维。
    -      batched = tf.expand_dims(
    -       tf.image.convert_image_dtype(img_data, tf.float32), 0)
    -      # 给出每一张图像的所有标注框。一个标注框有四个数字,分别代表[ymin, xmin, ymax, xmax]。 注意这里给出的数字都是图像的相对位置。比如在180×267的图像中,
    -      # [0.35, 0.47, 0.5, 0.56]代表了从(63,125)到(90,150)的图像。
    -      boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]])
    -      # 图7-11显示了加入了标注框的图像。
    -      result = tf.image.draw_bounding_boxes(batched, boxes)
    -     boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]])
    -     # 可以通过提供标注框的方式来告诉随机截取图像的算法哪些部分是“有信息量”的。
    -     begin, size, bbox_for_draw = tf.image.sample_distorted_bounding_box(
    -     tf.shape(img_data), bounding_boxes=boxes)
    -     # 通过标注框可视化随机截取得到的图像。得到的结果如图7-12左侧所示。
    -     batched = tf.expand_dims(
    -     tf.image.convert_image_dtype(img_data, tf. float32), 0)
    -     image_with_box = tf.image.draw_bounding_boxes(batched, bbox_for_draw)
    -     # 截取随机出来的图像。得到的结果如图7-12右侧所示。因为算法带有随机成分,所以 每次得到的结果会有所不同。
                -7.2.2 图像预处理完整样例
    -   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_contrast(image, lower=0.5, upper=1.5)
    -      image = tf.image.random_hue(image, max_delta=0.2)
    -      elif color_ordering == 2:
    -       # 还可以定义其他的排列,但在这里就不再一一列出。
    -      ...
    -      return tf.clip_by_value(image, 0.0, 1.0)
    -   # 给定一张解码后的图像、目标图像的尺寸以及图像上的标注框,此函数可以对给出的图像进行预 处理。这个函数的输入图像是图像识别问题中原始的训练图像,而输出则是神经网络模型的输入
    -   # 层。注意这里只处理模型的训练数据,对于预测的数据,一般不需要使用随机变换的步骤。
    -   def preprocess_for_train(image, height, width, bbox):
    -      # 如果没有提供标注框,则认为整个图像就是需要关注的部分。
    -      if bbox is None:
    -      bbox = tf.constant([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)
    -      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(2))
    -      return distorted_image
    -   image_raw_data = tf.gfile.FastGFile("/path/to/picture", "r").read()
    -   with tf.Session() as sess:
    -      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]]])
    -   # 运行6次获得6种不同的图像,在图7-13展示了这些图像的效果。
    -      for i in range(6):
    -       # 将图像的尺寸调整为299×299。
    -      result = preprocess_for_train(img_data, 299, 299, boxes)
    -      plt.imshow(result.eval())
    -      plt.show()
            -7.3 多线程输入数据处理框架
                -7.3.1 队列与多线程
    -   import tensorflow as tf
    -   # 创建一个先进先出队列,指定队列中最多可以保存两个元素,并指定类型为整数。
    -   q = tf.FIFOQueue(2, "int32")
    -   # 使用enqueue_many函数来初始化队列中的元素。和变量初始化类似,在使用队列之前 需要明确的调用这个初始化过程。
    -   init = q.enqueue_many(([0, 10],))
    -   # 使用Dequeue函数将队列中的第一个元素出队列。这个元素的值将被存在变量x中。
    -   x = q.dequeue()
    -   # 将得到的值加1。
    -   y = x + 1
    -   # 将加1后的值在重新加入队列。
    -   q_inc = q.enqueue([y])
    -   with tf.Session() as sess:
    -   # 运行初始化队列的操作。
    -   init.run()
    -   for _ in range(5):
    -       # 运行q_inc将执行数据出队列、出队的元素+1、重新加入队列的整个过程。
    -       v, _ = sess.run([x, q_inc])
    -       # 打印出队元素的取值。
    -       print v
    -   '''
    -   队列开始有[0,10]两个元素,第一个出队的为0,加1之后再次入队得到的队列为[10,1];第二次出队的为10,加1之后入队的为11,得到的队列为[1,11];以此类推,最后得到的输出为:
    -   0
    -   10
    -   1
    -   11
    -   2
    -   '''
    -   import tensorflow as tf
    -   import numpy as np
    -   import threading
    -   import time
    -   # 线程中运行的程序,这个程序每隔1秒判断是否需要停止并打印自己的ID。
    -   def MyLoop(coord, worker_id):
    -   # 使用tf.Coordinator类提供的协同工具判断当前线程是否需要停止。
    -   while not coord.should_stop():
    -       # 随机停止所有的线程。
    -       if np.random.rand() < 0.1 :
    -           print "Stoping from id: %d\n" % worker_id,
    -           # 调用coord.request_stop()函数来通知其他线程停止。
    -           coord.request_stop()
    -       else:
    -           # 打印当前线程的Id。
    -           print "Working on id: %d\n" % worker_id,
    -       # 暂停1秒
    -       time.sleep(1)
    -   # 声明一个tf.train.Coordinator类来协同多个线程。
    -   coord = tf.train.Coordinator()
    -   # 声明创建5个线程。
    -   threads = [
    -   threading.Thread(target=MyLoop, args=(coord, i, )) for i in xrange(5)]
    -   # 启动所有的线程。
    -   for t in threads: t.start()
    -   # 等待所有线程退出。
    -   coord.join(threads)
    -   Working on id: 0
    -   Working on id: 1
    -   Working on id: 2
    -   Working on id: 4
    -   Working on id: 3
    -   Working on id: 0
    -   Stoping from id: 4
    -   Working on id: 1
    -   import tensorflow as tf
    -   # 声明一个先进先出的队列,队列中最多100个元素,类型为实数。
    -   queue = tf.FIFOQueue(100, "float")
    -   # 定义队列的入队操作。
    -   enqueue_op = queue.enqueue([tf.random_normal([1])])
    -   # 使用tf.train.QueueRunner来创建多个线程运行队列的入队操作。 tf.train.QueueRunner的第一个参数给出了被操作的队列,[enqueue_op] * 5
    -   # 表示了需要启动5个线程,每个线程中运行的是enqueue_op操作。
    -   qr = tf.train.QueueRunner(queue, [enqueue_op] * 5)
    -   # 将定义过的QueueRunner加入TensorFlow计算图上指定的集合。 tf.train.add_queue_runner函数没有指定集合,
    -   # 则加入默认集合tf.GraphKeys.QUEUE_RUNNERS 。下面的函数就是将刚刚定义的 qr加入默认的tf.GraphKeys.QUEUE_RUNNERS集合。
    -   tf.train.add_queue_runner(qr)
    -   # 定义出队操作。
    -   out_tensor = queue.dequeue()
    -   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)
    -   '''
    -   上面的程序将启动五个线程来执行队列入队的操作,其中每一个线程都是将随机数写入队列。于是在每次运行出队操作时,可以得到一个随机数。运行这段程序可以得到类似下面的结果:
    -   -0.315963
    -   -1.06425
    -   0.347479
    -   '''
                -7.3.2 输入文件队列
    -   import tensorflow as tf
    -   # 创建TFRecord文件的帮助函数。
    -   def _int64_feature(value):
    -   return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
    -   # 模拟海量数据情况下将数据写入不同的文件。num_shards定义了总共写入多少个文件, instances_per_shard定义了每个文件中有多少个数据。
    -   num_shards = 2
    -   instances_per_shard = 2
    -   for i in range(num_shards):
    -   # 将数据分为多个文件时,可以将不同文件以类似0000n-of-0000m的后缀区分。其中m表 示了数据总共被存在了多少个文件中,n表示当前文件的编号。式样的方式既方便了通过正
    -   # 则表达式获取文件列表,又在文件名中加入了更多的信息。
    -   filename = ('/path/to/data.tfrecords-%.5d-of-%.5d' % (i, num_shards))
    -   writer = tf.python_io.TFRecordWriter(filename)
    -   # 将数据封装成Example结构并写入TFRecord文件。
    -   for j in range(instances_per_shard):
    -       # Example结构仅包含当前样例属于第几个文件以及是当前文件的第几个样本。
    -       example = tf.train.Example(features=tf.train.Features(feature={
    -           'i': _int64_feature(i),
    -           'j': _int64_feature(j)}))
    -       writer.write(example.SerializeToString())
    -   writer.close()
    -   import tensorflow as tf
    -   # 使用tf.train.match_filenames_once函数获取文件列表。
    -   files = tf.train.match_filenames_once("/path/to/data.tfrecords-*")
    -   # 通过tf.train.string_input_producer函数创建输入队列,输入队列中的文件列表为 tf.train.match_filenames_once函数获取的文件列表。这里将shuffle参数设为False
    -   # 来避免随机打乱读文件的顺序。但一般在解决真实问题时,会将shuffle参数设置为True。
    -   filename_queue = tf.train.string_input_producer(files, shuffle=False)
    -   # 如7.1节中所示读取并解析一个样本。
    -   reader = tf.TFRecordReader()
    -   _, serialized_example = reader.read(filename_queue)
    -   features = tf.parse_single_example(
    -     serialized_example,
    -     features={
    -         'i': tf.FixedLenFeature([], tf.int64),
    -         'j': tf.FixedLenFeature([], tf.int64),
    -     })
    -   with tf.Session() as sess:
    -     # 虽然在本段程序中没有声明任何变量,但使用tf.train.match_filenames_once函数时需 要初始化一些变量。
    -     tf.initialize_all_variables().run()
    -     '''
    -     打印文件列表将得到下面的结果:
    -     ['/path/to/data.tfrecords-00000-of-00002'
    -      '/path/to/data.tfrecords-00001-of-00002']
    -     '''
    -     print sess.run(files)
    -     # 声明tf.train.Coordinator类来协同不同线程,并启动线程。
    -     coord = tf.train.Coordinator()
    -     threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    -     # 多次执行获取数据的操作。
    -   for i in range(6):
    -     print sess.run([features['i'], features['j']])
    -   coord.request_stop()
    -   coord.join(threads)
    -   [0, 0]
    -   [0, 1]
    -   [1, 0]
    -   [1, 1]
    -   [0, 0]
    -   [0, 1]
    -   tensorflow.python.framework.errors.OutOfRangeError: FIFOQueue '_0_input_producer' is closed and has insufficient elements (requested 1, current size 0)
    -   [[Node: ReaderRead = ReaderRead[_class=["loc:@TFRecordReader", "loc: @input_producer"], _device="/job:localhost/replica:0/task:0/cpu:0"](TFRecordReader, input_producer)]]
                -7.3.3 组合训练数据(batching)
    -   import tensorflow as tf
    -   # 使用7.3.2小节中的方法读取并解析得到样例。这里假设Example结构中i表示一个样例的 特征向量,比如一张图像的像素矩阵。而j表示该样例对应的标签。
    -   example, label = features['i'], features['j']
    -   # 一个batch中样例的个数。
    -   batch_size = 3
    -   # 组合样例的队列中最多可以存储的样例个数。这个队列如果太大,那么需要占用很多内存资源; 如果太小,那么出队操作可能会因为没有数据而被阻碍(block),从而导致训练效率降低。一般
    -   # 来说这个队列的大小会和每一个batch的大小相关,下面一行代码给出了设置队列大小的一种 方式。
    -   capacity = 1000 + 3 * batch_size
    -   # 使用tf.train.batch函数来组合样例。[example, label]参数给出了需要组合的元素,  一般example和label分别代表训练样本和这个样本对应的正确标签。batch_size参数给出
    -   # 了每个batch中样例的个数。capacity给出了队列的最大容量。当队列长度等于容量时,  TensorFlow将暂停入队操作,而只是等待元素出队。当元素个数小于容量时,TensorFlow
    -   # 将自动重新启动入队操作。
    -   example_batch, label_batch = tf.train.batch(
    -   [example, label], batch_size=batch_size, capacity=capacity)
    -   with tf.Session() as sess:
    -   tf.initialize_all_variables().run()
    -   coord = tf.train.Coordinator()
    -   threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    -   # 获取并打印组合之后的样例。在真实问题中,这个输出一般会作为神经网络的输入。
    -   for i in range(2):
    -       cur_example_batch, cur_label_batch = sess.run(
    -           [example_batch, label_batch])
    -       print cur_example_batch, cur_label_batch
    -   coord.request_stop()
    -   coord.join(threads)
    -   '''
    -   运行上面的程序可以得到下面的输出:
    -   [0 0 1] [0 1 0]
    -   [1 0 0] [1 0 1]
    -   从这个输出可以看到tf.train.batch函数可以将单个的数据组织成3个一组的batch。
    -   在example, label中读到的数据依次为:
    -   example: 0, lable:0
    -   example: 0, lable:1
    -   example: 1, lable:0
    -   example: 1, lable:1
    -   这是因为tf.train.batch函数不会随机打乱顺序,所以组合之后得到的数据组合成了上面给出的输出。
    -   '''
    -   # 和tf.train.batch的样例代码一样产生example和label。
    -   example, label = features['i'], features['j']
    -   # 使用tf.train.shuffle_batch函数来组合样例。tf.train.shuffle_batch函数 的参数大部分都和tf.train.batch函数相似,但是min_after_dequeue参数是
    -   #  tf.train.shuffle_batch函数特有的。min_after_dequeue参数限制了出队时队列中元 素的最少个数。当队列中元素太少时,随机打乱样例顺序的作用就不大了。所以
    -   # tf.train.shuffle_batch函数提供了限制出队时最少元素的个数来保证随机打乱顺序的 作用。当出队函数被调用但是队列中元素不够时,出队操作将等待更多的元素入队才会完成。
    -   # 如果min_after_dequeue参数被设定,capacity也应该相应调整来满足性能需求。
    -   example_batch, label_batch = tf.train.shuffle_batch(
    -   [example, label], batch_size=batch_size,
    -   capacity=capacity, min_ after_dequeue=30)
    -   # 和tf.train.batch的样例代码一样打印example_batch, label_batch。
    -   '''
    -   运行上面的代码可以得到下面的输出:
    -   [0 1 1] [0 1 0]
    -   [1 0 0] [0 0 1]
    -   从输出中可以看到,得到的样例顺序已经被打乱了。
    -   '''
                -7.3.4 输入数据处理框架
    -   import tensorflow as tf
    -   # 创建文件列表,并通过文件列表创建输入文件队列。在调用输入数据处理流程前,需要 统一所有原始数据的格式并将它们存储到TFRecord文件中。下面给出的文件列表应该包含所
    -   # 有提供训练数据的TFRecord文件。
    -   files = tf.train.match_filenames_once("/path/to/file_pattern-*")
    -   filename_queue = tf.train.string_input_producer(files, shuffle=False)
    -   # 使用类似7.1节中介绍的方法解析TFRecord文件里的数据。这里假设image中存储的是图像 的原始数据,label为该样例所对应的标签。height、width和channels给出了图片的维度。
    -   reader = tf.TFRecordReader()
    -   _, serialized_example = reader.read(filename_queue)
    -   features = tf.parse_single_example(
    -     serialized_example,
    -     features={
    -         'image': tf.FixedLenFeature([], tf.string),
    -         'label': tf.FixedLenFeature([], tf.int64),
    -         'height': tf.FixedLenFeature([], tf.int64),
    -         'width': tf.FixedLenFeature([], tf.int64),
    -         'channels': tf.FixedLenFeature([], tf.int64),
    -     })
    -   image, label = features['image'], features['label']
    -   height, width = features['height'], features['width']
    -   channels = features['channels']
    -   # 从原始图像数据解析出像素矩阵,并根据图像尺寸还原图像。
    -   decoded_image = tf.decode_raw(image, tf.uint8)
    -   decoded_image.set_shape([height, width, channels])
    -   # 定义神经网络输入层图片的大小。
    -   image_size = 299
    -   # preprocess_for_train为7.2.2小节中介绍的图像预处理程序。
    -   distorted_image = preprocess_for_train(
    -   decoded_image, image_size, image_size, None)
    -   # 将处理后的图像和标签数据通过tf.train.shuffle_batch整理成神经网络训练时 需要的batch。
    -   min_after_dequeue = 10000
    -   batch_size = 100
    -   capacity = min_after_dequeue + 3 * batch_size
    -   image_batch, label_batch = tf.train.shuffle_batch(
    -   [distorted_image, label], batch_size=batch_size,
    -   capacity=capacity, min_after_dequeue=min_after_dequeue)
    -   # 定义神经网络的结构以及优化过程。image_batch可以作为输入提供给神经网络的输入层。 label_batch则提供了输入batch中样例的正确答案。
    -   logit = inference(image_batch)
    -   loss = calc_loss(logit, label_batch)
    -   train_step = tf.train.GradientDescentOptimizer(learning_rate)\
    -                 .minimize(loss)
    -   # 声明会话并运行神经网络的优化过程。
    -   with tf.Session() as sess:
    -   # 神经网络训练准备工作。这些工作包括变量初始化、线程启动。
    -   tf.initialize_all_variables().run()
    -   coord = tf.train.Coordinator()
    -   threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    -   # 神经网络训练过程。
    -   for i in range(TRAINING_ROUDNS):
    -       sess.run(train_step)
    -   # 停止所有线程。
    -   coord.request_stop()
    -   coord.join(threads)
            -小结
        -第8章 循环神经网络
            -8.1 循环神经网络简介 (1)
    -   import numpy as np
    -   X = [1, 2]
    -   state = [0.0, 0.0]
    -   # 分开定义不同输入部分的权重以方便操作。
    -   w_cell_state = np.asarray([[0.1, 0.2], [0.3, 0.4]])
    -   w_cell_input = np.asarray([0.5, 0.6])
    -   b_cell = np.asarray([0.1, -0.1])
    -   # 定义用于输出的全连接层参数。
    -   w_output = np.asarray([[1.0], [2.0]])
    -   b_output = 0.1
    -   # 按照时间顺序执行循环神经网络的前向传播过程。
    -   for i in range(len(X)):
    -   # 计算循环体中的全连接层神经网络。
    -   before_activation = np.dot(state, w_cell_state) +
    -                        X[i] * w_cell_input + b_cell
    -   state = np.tanh(before_activation)
    -   # 根据当前时刻状态计算最终输出。
    -   final_output = np.dot(state, w_output) + b_output
    -   # 输出每个时刻的信息。
    -   print "before activation: ", before_activation
    -   print "state: ", state
    -   print "output: ", final_output
    -   '''
            -8.2 长短时记忆网络(LSTM)结构
    -   # 定义一个LSTM结构。在TensorFlow中通过一句简单的命令就可以实现一个完整LSTM结构。 LSTM中使用的变量也会在该函数中自动被声明。
    -   lstm = rnn_cell.BasicLSTMCell(lstm_hidden_size)
    -   # 将LSTM中的状态初始化为全0数组。和其他神经网络类似,在优化循环神经网络时,每次也 会使用一个batch的训练样本。以下代码中,batch_size给出了一个batch的大小。
    -   # BasicLSTMCell类提供了zero_state函数来生成全领的初始状态。
    -   state = lstm.zero_state(batch_size, tf.float32)
    -   # 定义损失函数。
    -   loss = 0.0
    -   # 在8.1节中介绍过,虽然理论上循环神经网络可以处理任意长度的序列,但是在训练时为了 避免梯度消散的问题,会规定一个最大的序列长度。在以下代码中,用num_steps
    -   # 来表示这个长度。
    -   for i in range(num_steps):
    -    # 在第一个时刻声明LSTM结构中使用的变量,在之后的时刻都需要复用之前定义好的变量。
    -    if i > 0: tf.get_variable_scope().reuse_variables()
    -    # 每一步处理时间序列中的一个时刻。将当前输入(current_input)和前一时刻状态 (state)传入定义的LSTM结构可以得到当前LSTM结构的输出lstm_output和更新后
    -    # 的状态state。
    -    lstm_output, state = lstm(current_input, state)
    -    # 将当前时刻LSTM结构的输出传入一个全连接层得到最后的输出。
    -    final_output = fully_connected(lstm_output)
    -    # 计算当前时刻输出的损失。
    -    loss += calc_loss(final_output, expected_output)
    -   # 使用类似第4章中介绍的方法训练模型。
            -8.3 循环神经网络的变种
                -8.3.1 双向循环神经网络和深层循环神经网络
    -   # 定义个一个基本的LSTM结构作为循环体的基础结构。深层循环神经网络也支持使用其他的循环 体结。
    -   lstm = rnn_cell.BasicLSTMCell(lstm_size)
    -   # 通过MultiRNNCell类实现深层循环神经网络中每一个时刻的前向传播过程。其中 number_of_layers表示了有多少层,也就是图8-16中从xt到ht需要经过多少个LSTM结构。
    -   stacked_lstm = rnn_cell.MultiRNNCell([lstm] * number_of_layers)
    -   # 和经典的循环神经网络一样,可以通过zero_state函数来获取初始状态。
    -   state = stacked_lstm.zero_state(batch_size, tf.float32)
    -   # 和8.2节中给出的代码一样,计算每一时刻的前向传播结果。
    -   for i in range(len(num_steps)):
    -   if i> 0: tf.get_variable_scope().reuse_variables()
    -   stacked_lstm_output, state = stacked_lstm(current_input, state)
    -   final_output = fully_connected(stacked_lstm_output)
    -   loss += calc_loss(final_output, expected_output)
                -8.3.2 循环神经网络的dropout
    -   # 定义LSTM结构。
    -   lstm = rnn_cell.BasicLSTMCell(lstm_size)
    -   # 使用DropoutWrapper类来实现dropout功能。该类通过两个参数来控制dropout的概率, 一个参数为input_keep_prob,它可以用来控制输入的dropout概率 [(12)](part0015_split_005.html#ch12)
    -   # output_keep_prob,它可以用来控制输出的dropout概率。
    -   dropout_lstm = tf.nn.rnn_cell.DropoutWrapper(lstm, output_keep_prob=0.5)
    -   # 在使用了dropout的基础上定义
    -   stacked_lstm = rnn_cell.MultiRNNCell([dropout_lstm] * number_of_layers)
    -   # 和8.3.1小节中深层循环网络样例程序类似,运行前向传播过程。
            -8.4 循环神经网络样例应用
                -8.4.1 自然语言建模
    -   http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz
    -   1-train/
    -   2-nbest-rescore/
    -   3-combination/
    -   4-data-generation/
    -   5-one-iter/
    -   6-recovery-during-training/
    -   7-dynamic-evaluation/
    -   8-direct/
    -   9-char-based-lm/
    -   data/
    -   models/
    -   rnnlm-0.2b/
    -   ptb.test.txt    # 测试集数据文件
    -   ptb.train.txt    # 训练集数据文件
    -   ptb.valid.txt    # 验证集数据文件
    -   mr.  is chairman of  n.v. the dutch publishing group
    -   from tensorflow.models.rnn.ptb import reader
    -   # 存放原始数据的路径。
    -   DATA_PATH = "/path/to/ptb/data"
    -   train_data, valid_data, test_data, _ = reader.ptb_raw_data(DATA_PATH)
    -   # 读取数据原始数据。
    -   print len(train_data)
    -   print train_data[:100]
    -   '''
    -   运行以上程序可以得到输出:
    -   929589
    -   [9970, 9971, 9972, 9974, 9975, 9976, 9980, 9981, 9982, 9983, 9984, 9986, 9987, 9988, 9989, 9991, 9992, 9993, 9994, 9995, 9996, 9997, 9998, 9999, 2, 9256, 1, 3, 72, 393, 33, 2133, 0, 146, 19, 6, 9207, 276, 407, 3, 2, 23, 1, 13, 141, 4, 1, 5465, 0, 3081, 1596, 96, 2, 7682, 1, 3, 72, 393, 8, 337, 141, 4, 2477, 657, 2170, 955, 24, 521, 6, 9207, 276, 4, 39, 303, 438, 3684, 2, 6, 942, 4, 3150, 496, 263, 5, 138, 6092, 4241, 6036, 30, 988, 6, 241, 760, 4, 1015, 2786, 211, 6, 96, 4]
    -   '''
    -   from tensorflow.models.rnn.ptb import reader
    -   # 类似地读取数据原始数据。
    -   DATA_PATH = "/path/to/ptb/data"
    -   train_data, valid_data, test_data, _ = reader.ptb_raw_data(DATA_PATH)
    -   # 将训练数据组织成batch大小为4、截断长度为5的数据组。
    -   result = reader.ptb_iterator(train_data, 4, 5)
    -   # 读取第一个batch中的数据,其中包括每个时刻的输入和对应的正确输出。
    -   x, y = result.next()
    -   print "X:", x
    -   print "y:", y
    -   '''
    -   运行以上程序可以得到输出:
    -   X: [[9970 9971 9972 9974 9975]
    -   [ 332 7147  328 1452 8595]
    -    [1969    0   98   89 2254]
    -    [   3    3    2   14   24]]
    -   y: [[9971 9972 9974 9975 9976]
    -    [7147  328 1452 8595   59]
    -    [   0   98   89 2254    0]
    -    [   3    2   14   24  198]]
    -   '''
    -   # -*- coding: utf-8 -*-
    -   import numpy as np
    -   import tensorflow as tf
    -   from tensorflow.models.rnn.ptb import reader
    -   DATA_PATH = "/path/to/ptb/data"        # 数据存放的路径。
    -   HIDDEN_SIZE = 200                     # 隐藏层规模。
    -   NUM_LAYERS = 2                         # 深层循环神经网络中LSTM结构的层数。
    -   VOCAB_SIZE = 10000                    # 词典规模,加上语句结束标识符和稀有 单词标识符总共一万个单词。
    -   LEARNING_RATE = 1.0                    # 学习速率。
    -   TRAIN_BATCH_SIZE = 20                 # 训练数据batch的大小。
    -   TRAIN_NUM_STEP = 35                   # 训练数据截断长度。 在测试时不需要使用截断,所以可以将测试数据看成一个超长的序列。
    -   EVAL_BATCH_SIZE = 1                   # 测试数据batch的大小。
    -   EVAL_NUM_STEP = 1                      # 测试数据截断长度。
    -   NUM_EPOCH = 2                           # 使用训练数据的轮数。
    -   KEEP_PROB = 0.5                        # 节点不被dropout的概率。
    -   MAX_GRAD_NORM = 5                      # 用于控制梯度膨胀的参数。 通过一个PTBModel类来描述模型,这样方便维护循环神经网络中的状态。
    -   class PTBModel(object):
    -   def __init__(self, is_training, batch_size, num_steps):
    -       # 记录使用的batch大小和截断长度。
    -       self.batch_size = batch_size
    -       self.num_steps = num_steps
    -       # 定义输入层。可以看到输入层的维度为batch_size × num_steps,这和 ptb_iterator函数输出的训练数据batch是一致的。
    -       self.input_data = tf.placeholder(tf.int32, [batch_size, num_steps])
    -       # 定义预期输出。它的维度和ptb_iterator函数输出的正确答案维度也是一样的。
    -       self.targets = tf.placeholder(tf.int32, [batch_size, num_steps])
    -       # 定义使用LSTM结构为循环体结构且使用dropout的深层循环神经网络。
    -       lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE)
    -       if is_training :
    -           lstm_cell = tf.nn.rnn_cell.DropoutWrapper(
    -               lstm_cell, output_keep_prob=KEEP_PROB)
    -       cell = tf.nn.rnn_cell.MultiRNNCell([lstm_cell] * NUM_LAYERS)
    -       # 初始化最初的状态,也就是全零的向量。
    -       self.initial_state = cell.zero_state(batch_size, tf.float32)
    -       # 将单词ID转换成为单词向量。因为总共有VOCAB_SIZE个单词,每个单词向量的维度 为HIDDEN_SIZE,所以embedding参数的维度为VOCAB_SIZE × HIDDEN_SIZE [(14)](part0015_split_005.html#ch14)
    -       embedding = tf.get_variable("embedding", [VOCAB_SIZE, HIDDEN_SIZE])
    -       # 将原本batch_size × num_steps个单词ID转化为单词向量,转化后的输入层维度 为batch_size × num_steps × HIDDEN_SIZE。
    -       inputs = tf.nn.embedding_lookup(embedding, self.input_data)
    -       # 只在训练时使用dropout。
    -       if is_training: inputs = tf.nn.dropout(inputs, KEEP_PROB)
    -       # 定义输出列表。在这里先将不同时刻LSTM结构的输出收集起来,再通过一个全连接 层得到最终的输出。
    -       outputs = []
    -       # state 存储不同batch中LSTM的状态,将其初始化为0。
    -       state = self.initial_state
    -       with tf.variable_scope("RNN"):
    -           for time_step in range(num_steps):
    -               if time_step > 0: tf.get_variable_scope().reuse_variables()
    -               # 从输入数据中获取当前时刻获的输入并传入LSTM结构。
    -               cell_output, state = cell(inputs[:, time_step, :], state)
    -               # 将当前输出加入输出队列。
    -               outputs.append(cell_output)
    -       # 把输出队列展开成[batch, hidden_size*num_steps]的形状,然后再 reshape成[batch*numsteps, hidden_size]的形状。
    -       output = tf.reshape(tf.concat(1, outputs), [-1, HIDDEN_SIZE])
    -       # 将从LSTM中得到的输出再经过一个全链接层得到最后的预测结果,最终的预测结果在 每一个时刻上都是一个长度为VOCAB_SIZE的数组,经过softmax层之后表示下一个
    -       # 位置是不同单词的概率。
    -       weight = tf.get_variable("weight", [HIDDEN_SIZE, VOCAB_SIZE])
    -       bias = tf.get_variable("bias", [VOCAB_SIZE])
    -       logits = tf.matmul(output, weight) + bias
    -       # 定义交叉熵损失函数。TensorFlow提供了sequence_loss_by_example函数来计 算一个序列的交叉熵的和。
    -       loss = tf.nn.seq2seq.sequence_loss_by_example(
    -           [logits],                                  # 预测的结果。
    -           [tf.reshape(self.targets, [-1])],      # 期待的正确答案,这里将 [batch_size, num_steps]
    -                                                        # 二维数组压缩成一维数组。 损失的权重。在这里所有的权重都为1,也就是说不同batch和不同时刻
    -           # 的重要程度是一样的。
    -           [tf.ones([batch_size * num_steps], dtype=tf.float32)])
    -       # 计算得到每个batch的平均损失。
    -       self.cost = tf.reduce_sum(loss) / batch_size
    -       self.final_state = state
    -       # 只在训练模型时定义反向传播操作。
    -       if not is_training: return
    -       trainable_variables = tf.trainable_variables()
    -       # 通过clip_by_global_norm函数控制梯度的大小,避免梯度膨胀的问题。
    -       grads, _ = tf.clip_by_global_norm(
    -           tf.gradients(self.cost, trainable_variables), MAX_GRAD_NORM)
    -       # 定义优化方法。
    -       optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE)
    -       # 定义训练步骤。
    -       self.train_op = optimizer.apply_gradients(
    -            zip(grads, trainable_variables))
    -   # 使用给定的模型model在数据data上运行train_op并返回在全部数据上的perplexity值。
    -   def run_epoch(session, model, data, train_op, output_log):
    -   # 计算perplexity的辅助变量。
    -   total_costs = 0.0
    -   iters = 0
    -   state = session.run(model.initial_state)
    -   # 使用当前数据训练或者测试模型。
    -   for step, (x, y) in enumerate(
    -       reader.ptb_iterator(data, model.batch_size, model.num_steps)):
    -       # 在当前batch上运行train_op并计算损失值。交叉熵损失函数计算的就是下一个单 词为给定单词的概率。
    -       cost, state, _ = session.run(
    -           [model.cost, model.final_state, train_op],
    -           {model.input_data: x, model.targets: y,
    -            model.initial_state: state})
    -       # 将不同时刻、不同batch的概率加起来就可以得到第二个perplexity公式等号右 边的部分,再将这个和做指数运算就可以得到perplexity值。
    -       total_costs += cost
    -       iters += model.num_steps
    -       # 只有在训练时输出日志。
    -       if output_log and step % 100 == 0:
    -           print("After %d steps, perplexity is %.3f" % (
    -                 step, np.exp(total_costs / iters)))
    -   # 返回给定模型在给定数据上的perplexity值。
    -   return np.exp(total_costs / iters)
    -   def main(_):
    -   # 获取原始数据。
    -   train_data, valid_data, test_data, _ = reader.ptb_raw_data(DATA_PATH)
    -   # 定义初始化函数。
    -   initializer = tf.random_uniform_initializer(-0.05, 0.05)
    -   # 定义训练用的循环神经网络模型。
    -   with tf.variable_scope("language_model",
    -                             reuse=None, initializer=initializer):
    -       train_model = PTBModel(True, TRAIN_BATCH_SIZE, TRAIN_NUM_STEP)
    -   # 定义评测用的循环神经网络模型。
    -   with tf.variable_scope("language_model",
    -                             reuse=True, initializer=initializer):
    -       eval_model = PTBModel(False, EVAL_BATCH_SIZE, EVAL_NUM_STEP)
    -   with tf.Session() as session:
    -       tf.initialize_all_variables().run()
    -       # 使用训练数据训练模型。
    -       for i in range(NUM_EPOCH):
    -           print("In iteration: %d" % (i + 1))
    -           # 在所有训练数据上训练循环神经网络模型。
    -           run_epoch(session, train_model,
    -                       train_data, train_model.train_op, True)
    -           # 使用验证数据评测模型效果。
    -           valid_perplexity = run_epoch(
    -                  session, eval_model, valid_data, tf.no_op(), False)
    -           print("Epoch: %d Validation Perplexity: %.3f" % (
    -               i + 1, valid_perplexity))
    -       # 最后使用测试数据测试模型效果。
    -       test_perplexity = run_epoch(
    -            session, eval_model, test_data, tf.no_op(), False)
    -       print("Test Perplexity: %.3f" % test_perplexity)
    -   if __name__ == "__main__":
    -   tf.app.run()
    -:
    -   In iteration: 1
    -   After 0 steps, perplexity is 10003.783
    -   After 100 steps, perplexity is 1404.742
    -   After 200 steps, perplexity is 1061.458
    -   After 300 steps, perplexity is 891.044
    -   After 400 steps, perplexity is 782.037
    -   …
    -   After 1100 steps, perplexity is 228.711
    -   After 1200 steps, perplexity is 226.093
    -   After 1300 steps, perplexity is 223.214
    -   Epoch: 2 Validation Perplexity: 183.443
    -   Test Perplexity: 179.420
                -书名页
    -8.4.2 时间序列预测
    -,图8-12给出了sin函数的函数图像。在给出具体的TensorFlow代码之前,本小节将先介绍另外一个对TensorFlow的高层封装——TFLearn [(17)](part0015_split_005.html#ch17)
    -。和第6章中介绍的TensorFlow-Slim类似,通过使用TFLearn可以让TensorFlow代码效率进一步提高。
    -。以下程序展示了如何通过TFLearn快速的解决iris分类问题。
    -   # -*- coding: utf-8 -*- 为了方便数据处理,本程序使用了sklearn工具包,关于这个工具包更多的信息可以参考
    -   # http://scikit-learn.org/。
    -   from sklearn import cross_validation
    -   from sklearn import datasets
    -   from sklearn import metrics
    -   import tensorflow as tf
    -   # 导入TFLearn。
    -   learn = tf.contrib.learn
    -   # 自定义模型,对于给定的输入数据(features)以及其对应的正确答案(target),返回在这 些输入上的预测值、损失值以及训练步骤。
    -   def my_model(features, target):
    -   # 将预测的目标转换为one-hot编码的形式,因为共有三个类别,所以向量长度为3。经过转 化后,第一个类别表示为(1,0,0),第二个为(0,1,0),第三个为(0,0,1)。
    -   target = tf.one_hot(target, 3, 1, 0)
    -   # 定义模型以及其在给定数据上的损失函数。TFLearn通过logistic_regression封装了 一个单层全连接神经网络。
    -   logits, loss = learn.models.logistic_regression(features, target)
    -   # 创建模型的优化器,并得到优化步骤。
    -   train_op = tf.contrib.layers.optimize_loss(
    -       loss,                                             # 损失函数
    -       tf.contrib.framework.get_global_step(),     # 获取训练步数并在训练时更新
    -       optimizer='Adagrad',                           # 定义优化器
    -       learning_rate=0.1)                              # 定义学习率 返回在给定数据上的预测结果、损失值以及优化步骤。
    -   return tf.arg_max(logits, 1), loss, train_op
    -   # 加载iris数据集,并划分为训练集合和测试集合。
    -   iris = datasets.load_iris()
    -   x_train, x_test, y_train, y_test = cross_validation.train_test_split(
    -   iris.data, iris.target, test_size=0.2, random_state=0)
    -   # 对自定义的模型进行封装。
    -   classifier = learn.Estimator(model_fn=my_model)
    -   # 使用封装好的模型和训练数据执行100轮迭代。
    -   classifier.fit(x_train, y_train, steps=100)
    -   # 使用训练好的模型进行结果预测。
    -   y_predicted = classifier.predict(x_test)
    -   # 计算模型的准确度。
    -   score = metrics.accuracy_score(y_test, y_predicted)
    -   print('Accuracy: %.2f%%' % (score * 100))
    -   '''
    -   运行以上程序可以得到输出:
    -   Accuracy: 90.00%
    -   '''
    -   # -*- coding: utf-8 -*-
    -   import numpy as np
    -   import tensorflow as tf
    -   # 加载matplotlib工具包,使用该工具可以对预测的sin函数曲线进行绘图。
    -   import matplotlib as mpl
    -   mpl.use('Agg')
    -   from matplotlib import pyplot as plt
    -   learn = tf.contrib.learn
    -   HIDDEN_SIZE = 30                               # LSTM中隐藏节点的个数。
    -   NUM_LAYERS = 2 # LSTM的层数。
    -   TIMESTEPS = 10                                 # 循环神经网络的截断长度。
    -   TRAINING_STEPS = 10000                         # 训练轮数。
    -   BATCH_SIZE = 32                              # batch大小。
    -   TRAINING_EXAMPLES = 10000                   # 训练数据个数。
    -   TESTING_EXAMPLES = 1000                         # 测试数据个数。
    -   SAMPLE_GAP = 0.01                              # 采样间隔。
    -   def generate_data(seq):
    -   X = []
    -   y = []
    -   # 序列的第i项和后面的TIMESTEPS-1项合在一起作为输入;第i + TIMESTEPS项作为输 出。即用sin函数前面的TIMESTEPS个点的信息,预测第i + TIMESTEPS个点的函数值。
    -   for i in range(len(seq) - TIMESTEPS - 1):
    -       X.append([seq[i: i + TIMESTEPS]])
    -       y.append([seq[i + TIMESTEPS]])
    -   return np.array(X, dtype=np.float32), np.array(y, dtype=np.float32)
    -   def lstm_model(X, y):
    -   # 使用多层的lstm结构。
    -   lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE)
    -   cell = tf.nn.rnn_cell.MultiRNNCell([lstm_cell] * NUM_LAYERS)
    -   x_ = tf.unpack(X, axis=1) [(19)](part0015_split_005.html#ch19)
    -   # 使用TensorFlow接口将多层的LSTM结构连接成RNN网络并计算其前向传播结果。
    -   output, _ = tf.nn.rnn(cell, x_, dtype=tf.float32)
    -   # 在本问题中只关注最后一个时刻的输出结果,该结果为下一时刻的预测值。
    -   output = output[-1]
    -   # 对LSTM网络的输出再做加一层全链接层并计算损失。注意这里默认的损失为平均 平方差损失函数。
    -   prediction, loss = learn.models.linear_regression(output, y)
    -   # 创建模型优化器并得到优化步骤。
    -   train_op = tf.contrib.layers.optimize_loss(
    -       loss, tf.contrib.framework.get_global_step(),
    -       optimizer="Adagrad", learning_rate=0.1)
    -   return prediction, loss, train_op
    -   # 建立深层循环网络模型。
    -   regressor = learn.Estimator(model_fn=lstm_model)
    -   # 用正弦函数生成训练和测试数据集合。 numpy.linspace函数可以创建一个等差序列的数组,它常用的参数有三个参数,第一个参数
    -   # 表示起始值,第二个参数表示终止值,第三个参数表示数列的长度。例如,linespace(1,10,10) 产生的数组是arrray([1,2,3,4,5,6,7,8,9,10])。
    -   test_start = TRAINING_EXAMPLES * SAMPLE_GAP
    -   test_end = (TRAINING_EXAMPLES + TESTING_EXAMPLES) * SAMPLE_GAP
    -   train_X, train_y = generate_data(np.sin(np.linspace(
    -   0, test_start, TRAINING_EXAMPLES, dtype=np.float32)))
    -   test_X, test_y = generate_data(np.sin(np.linspace(
    -   test_start, test_end, TESTING_EXAMPLES, dtype=np.float32)))
    -   # 调用fit函数训练模型。
    -   regressor.fit(train_X, train_y, batch_size=BATCH_SIZE,
    -                steps=TRAINING_STEPS)
    -   # 使用训练好的模型对测试数据进行预测。
    -   predicted = [[pred] for pred in regressor.predict(test_X)]
    -   # 计算rmse作为评价指标。
    -   rmse = np.sqrt(((predicted - test_y) ** 2).mean(axis=0))
    -   print ("Mean Square Error is: %f" % rmse[0])
    -   '''
    -   运行以上程序可以得到输出: [(20)](part0015_split_005.html#ch20)
    -   Mean Square Error is: 0.002183
    -   从输出可以看出通过循环神经网络可以非常精确的预测正弦函数sin的取值。
    -   '''
    -   #对预测的sin函数曲线进行绘图,并存储到运行目录下的sin.png
    -   fig = plt.figure()
    -   plot_predicted = plt.plot(predicted, label='predicted')
    -   plot_test = plt.plot(test_y, label='real_sin')
    -   plt.legend([plot_predicted, plot_test], ['predicted', 'real_sin'])
    -   # 得到的结果如图8-21所示。
    -   fig.savefig('sin.png')
            - 小结
    -  本节内容部分参考了资料http://colah.github.io/posts/2015-08-Understanding-LSTMs/。
    -  参见:Sathasivam S. Logic Learning in Hopfield Networks
    -[J]. Modern Applied Science, 2009.
    - 本章关于循环神经网络的介绍图片部分来自资料http://colah.github.io/posts/2015-08-Understanding- LSTMs/。
    - 关于单词向量的简单介绍可参考第1章1.3节。
    - 关于单词向量更加详细的介绍可以参考论文:Mikolov T, Sutskever I, Chen K, et al. Distributed Representations of Words and Phrases and their Compositionality
    -[J]. Advances in Neural Information Processing Systems, 2013, 26:3111-3119.
    - 图中中间标有tanh的小方框表示一个使用了tanh作为激活函数的全连接神经网络。
    - 也有资料中将会将上一时刻状态对应的权重和当前时刻输入对应的权重特意分开,但它们的实质是一样的。本节展示样例中为了方便显示,采用了向量拼接的方式;在本节的代码中为了方便代码编写,采用了分开的方式。
    - 参见:Gustavsson A, Magnuson A, Blomberg B, et al. On the difficulty of training Recurrent Neural Networks
    -[J]. Computer Science, 2013.
    - Sepp Hochreiter, Jürgen Schmidhuber. Long short-term memory
    -[J]. Neural Computation. 9 (8): 1735~1780,1997.
    - Schuster M, Paliwal K K. Bidirectional recurrent neural networks
    -[J]. IEEE Transactions on Signal Processing, 1997.
    - Zaremba W, Sutskever I, Vinyals O. Recurrent Neural Network Regularization
    -[J]. Eprint Arxiv, 2014.
    - 注意这里定义的实际上是节点被保留的概率。如果给出的数字为0.9,那么只有10%的节点会被dropout。
    - Bttcher S, Clarke C L A, Cormack G V. Information Retrieval: Implementing and Evaluating Search Engines
    -[M]. The MIT Press, 2016.
    - 关于更多关于使用TensorFlow实现单词向量的资料可以参考TensorFlow官方网站:https://www. tensorflow.org/tutorials/word2vec/。
    - 在TensorFlow 0.9.0下运行会提示:“WARNING:tensorflow:: Using a concatenated state is slower and will soon be deprecated. Use state_is_tuple=True.”这不会影响运行。但是TensorFlow0.9.0对state_is_tupe=True不支持,所以书中没有设置,在TensorFlow更高的版本中可以将state_is_tuple参数设置为True。
    - 本小节部分内容参考自:http://mourafiq.com/2016/05/15/predicting-sequences-using-rnn-in-tensorflow.html
    - TFLearn又名skflow,它们是同一套系统。
    - 更多关于iris数据集的信息可以参考:http://archive.ics.uci.edu/ml/datasets/Iris。
    - 此处要求TensorFlow0.10.0及以上版本。
    - 运行该程序可能会因为TFLearn的版本而得到一些warning,但这些warning不会影响程序的正常运行。
        -第9章 TensorBoard可视化
            -9.1 TensorBoard简介
    -   import tensorflow as tf
    -   # 定义一个简单的计算图,实现向量加法的操作。
    -   input1 = tf.constant([1.0, 2.0, 3.0], name="input1")
    -   input2 = tf.Variable(tf.random_uniform([3]), name="input2")
    -   output = tf.add_n([input1, input2], name="add")
    -   # 生成一个写日志的writer,并将当前的TensorFlow计算图写入日志。TensorFlow提供了多 种写日志文件的API,在9.3节中将详细介绍。
    -   writer = tf.train.SummaryWriter("/path/to/log", tf.get_default_graph())
    -   writer.close()
    -   # 运行TensorBoard,并将日志的地址指向上面程序日志输出的地址。
    -   tensorboard --logdir=/path/to/log
            -9.2 TensorFlow计算图可视化
                -9.2.1 命名空间与TensorBoard图上节点
    -   import tensorflow as tf
    -   with tf.variable_scope("foo"):
    -   # 在命名空间foo下获取变量“bar”,于是得到的变量名称为“foo/bar”。
    -   a = tf.get_variable("bar", [1])
    -   print a.name                                # 输出:foo/bar:0
    -   with tf.variable_scope("bar"):
    -   # 在命名空间bar下获取变量“bar”,于是得到的变量名称为“bar/bar”。此时变量 “bar/bar”和变量“foo/bar”并不冲突,于是可以正常运行。
    -   b = tf.get_variable("bar", [1])
    -   print b.name                                # 输出:bar/bar:0
    -   with tf.name_scope("a"):
    -   # 使用tf.Variable函数生成变量会受tf.name_scope影响,于是这个变量的名称 为“a/Variable”。
    -   a = tf.Variable([1])
    -   print a.name                                # 输出:a/Variable:0 tf.get_variable函数不受tf.name_scope函数的影响,
    -   # 于是变量并不在a这个命名空间中。
    -   a = tf.get_variable("b", [1])
    -   print a.name                                        # 输出:b:0
    -   with tf.name_scope("b"):
    -   # 因为tf.get_variable不受tf.name_scope影响,所以这里将试图获取名称 为“a”的变量。然而这个变量已经被声明了,于是这里会报重复声明的错误:
    -   # ValueError: Variable bar already exists, disallowed. Did you mean  to set reuse=True in VarScope?  Originally defined at: …
    -   tf.get_variable("b", [1])
    -书名页
    -   # 将输入定义放入各自的命名空间中,从而使得TensorBoard可以根据命名空间来整理可视化效 果图上的节点。
    -   with tf.name_scope("input1"):
    -   input1 = tf.constant([1.0, 2.0, 3.0], name="input1")
    -   with ctf.name_scope("input2"):
    -   input2 = tf.Variable(tf.random_uniform([3]), name="input2")
    -   output = tf.add_n([input1, input2], name="add")
    -   writer = tf.train.SummaryWriter("/path/to/log", tf.get_default_graph())
    -   writer.close()
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   # mnist_inference中定义的常量和前向传播的函数不需要改变,因为前向传播已经通过 tf.variable_scope实现了计算节点按照网络结构的划分。
    -   import mnist_inference
    -   INPUT_NODE = 784
    -   OUTPUT_NODE = 10
    -   LAYER1_NODE = 500
    -   def train(mnist):
    -      # 将处理输入数据的计算都放在名字为“input”的命名空间下。
    -      with tf.name_scope('input'):
    -      x = tf.placeholder(
    -           tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')
    -      y_ = tf.placeholder(
    -           tf.float32, [None, mnist_inference.OUTPUT_NODE],
    -           name='y-cinput')
    -      regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    -      y = mnist_inference.inference(x, regularizer)
    -      global_step = tf.Variable(0, trainable=False)
    -   # 将处理滑动平均相关的计算都放在名为moving_average的命名空间下。
    -   with tf.name_scope("moving_average"):
    -       variable_averages = tf.train.ExponentialMovingAverage(
    -            MOVING_AVERAGE_DECAY, global_step)
    -       variables_averages_op = variable_averages.apply(
    -            tf.trainable_variables())
    -   # 将计算损失函数相关的计算都放在名为loss_function的命名空间下。
    -   with tf.name_scope("loss_function"):
    -      cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
    -           y, tf.argmax(y_, 1))
    -      cross_entropy_mean = tf.reduce_mean(cross_entropy)
    -      loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    -   # 将定义学习率、优化方法以及每一轮训练需要执行的操作都放在名字为“train_step” 的命名空间下。
    -   with tf.name_scope("train_step"):
    -       learning_rate = tf.train.exponential_decay(
    -           LEARNING_RATE_BASE,
    -            global_step,
    -            mnist.train.num_examples / BATCH_SIZE,
    -            LEARNING_RATE_DECAY,
    -            staircase=True)
    -       train_step = tf.train.GradientDescentOptimizer(learning_rate)\
    -                         .minimize(loss, global_step=global_step)
    -       with tf.control_dependencies([train_step, variables_averages_op]):
    -           train_op = tf.no_op(name='train')
    -       # 使用和5.5节中一样的方式训练神经网络。
    -        …
    -   # 将当前的计算图输出到TensorBoard日志文件。
    -   writer = tf.train.SummaryWriter("/path/to/log", tf.get_default_graph())
    -   writer.close()
    -   def main(argv=None):
    -   mnist = input_data.read_data_sets("/tmp/data", one_hot=True)
    -   train(mnist)
    -   if __name__ == '__main__':
    -   tf.app.run()
            -9.2.2 节点信息
    -   with tf.Session() as sess:
    -       tf.initialize_all_variables().run()
    -       for i in range(TRAINING_STEPS):
    -           xs, ys = mnist.train.next_batch(BATCH_SIZE)
    -           # 每1000轮记录一次运行状态。
    -           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))
    -           else:
    -               _, loss_value, step = sess.run(
    -                  [train_op, loss, global_step], feed_dict={x: xs, y_: ys})
            -9.3 监控指标可视化
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   SUMMARY_DIR = "/path/to/log"
    -   BATCH_SIZE = 100
    -   TRAIN_STEPS = 30000
    -   # 生成变量监控信息并定义生成监控信息日志的操作。其中var给出了需要记录的张量,name给 出了在可视化结果中显示的图表名称,这个名称一般与变量名一致。
    -   def variable_summaries(var, name):
    -   # 将生成监控信息的操作放到同一个命名空间下。
    -   with tf.name_scope('summaries'):
    -       # 通过tf.histogram_summary函数记录张量中元素的取值分布。对于给出的图表名称 和张量,tf.histogram_summary函数会生成一个Summary protocol buffer。
    -       # 将Summary写入 TensorBoard日志文件后,可以在HISTOGRAMS栏下看到对应名 称的图表。图9-20给出了一个可视化结果效果图。和TensorFlow中其他操作类似,
    -       # tf.histogram_summary函数不会立刻被执行,只有当sess.run函数明确调用这 个操作时,TensorFlow才会真正生成并输出Summary protocol buffer。
    -       tf.histogram_summary(name, var)
    -       # 计算变量的平均值,并定义生成平均值信息日志的操作。记录变量平均值信息的日志标签名 为'mean/' + name,其中mean为命名空间,/是命名空间的分隔符。从图9-17
    -       # 中可以看到,在相同命名空间中的监控指标会被整合到同一栏中。name则给出了当前监 控指标属于哪一个变量。
    -       mean = tf.reduce_mean(var)
    -       tf.scalar_summary('mean/' + name, mean)
    -       # 计算变量的标准差,并定义生成其日志的操作。
    -       stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
    -       tf.scalar_summary('stddev/' + name, stddev)
    -   # 生成一层全链接层神经网络。
    -   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.histogram_summary(layer_name + '/pre_activations',
    -                                    preactivate)
    -       activations = act(preactivate, name='activation')
    -       # 记录神经网络输出节点在经过激活函数之后的分布。在图9-20中,对于layer1,因 为使用了ReLU函数作为激活函数,所以所有小于0的值都被设为了0。于是在激活后
    -       # 的layer1/activations图上所有的值都是大于0的。而对于layer2,因为没有使 用激活函数,所以layer2/activations和layer2/pre_activations一样。
    -       tf.histogram_summary(layer_name + '/activations', activations)
    -       return activations
    -   def main(_):
    -   mnist = input_data.read_data_sets("/tmp/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.image_summary函数定义将当前的图片信 息写入日志的操作。
    -   with tf.name_scope('input_reshape'):
    -       image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
    -       tf.image_summary('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(y, y_))
    -       tf.scalar_summary('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.scalar_summary('accuracy', accuracy)
    -   # 和TensorFlow中其他操作类似,tf.scalar_summary、tf.histogram_summary 和tf.image_summary函数都不会立即执行,需要通过sess.run来明确调用这些函数。
    -   # 因为程序中定义的写日志操作比较多,一一调用非常麻烦,所以TensorFlow提供了 tf.merge_all_summaries函数来整理所有的日志生成操作。在TensorFlow程序执行
    -   # 的过程中只需要运行这个操作就可以将代码中定义的所有日志生成操作执行一次,从而将所 有日志写入文件。
    -   merged = tf.merge_all_summaries()
    -   with tf.Session() as sess:
    -       # 初始化写日志的writer,并将当前TensorFlow计算图写入日志。
    -       summary_writer = tf.train.SummaryWriter(SUMMARY_DIR, sess.graph)
    -       tf.initialize_all_variables().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()
    -   if __name__ == '__main__':
    -   tf.app.run()
            -小结
        -第10章 TensorFlow计算加速
            -10.1 TensorFlow使用GPU
    -   import tensorflow as tf
    -   a = tf.constant([1.0, 2.0, 3.0], shape=[3], name='a')
    -   b = tf.constant([1.0, 2.0, 3.0], shape=[3], name='b')
    -   c = a + b
    -   # 通过log_device_placement参数来输出运行每一个运算的设备。
    -   sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
    -   print sess.run(c)
    -   '''
    -   在没有GPU的机器上运行以上代码可以得到以下输出:
    -   Device mapping: no known devices.
    -   add: /job:localhost/replica:0/task:0/cpu:0
    -   b: /job:localhost/replica:0/task:0/cpu:0
    -   a: /job:localhost/replica:0/task:0/cpu:0
    -   [ 2\.  4\.  6.]
    -   '''
    -   Device mapping:
    -   /job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GRID K520, pci bus id: 0000:00:03.0
    -   /job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: GRID K520, pci bus id: 0000:00:04.0
    -   /job:localhost/replica:0/task:0/gpu:2 -> device: 2, name: GRID K520, pci bus id: 0000:00:05.0
    -   /job:localhost/replica:0/task:0/gpu:3 -> device: 3, name: GRID K520, pci bus id: 0000:00:06.0
    -   add: /job:localhost/replica:0/task:0/gpu:0
    -   b: /job:localhost/replica:0/task:0/gpu:0
    -   a: /job:localhost/replica:0/task:0/gpu:0
    -   [ 2\.  4\.  6.]
    -   import tensorflow as tf
    -   # 通过tf.device将运算指定到特定的设备上。
    -   with tf.device('/cpu:0'):
    -      a = tf.constant([1.0, 2.0, 3.0], shape=[3], name='a')
    -      b = tf.constant([1.0, 2.0, 3.0], shape=[3], name='b')
    -   with tf.device('/gpu:1'):
    -   c = a + b
    -   sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
    -   print sess.run(c)
    -   '''
    -   在AWS g2.8xlarge实例上运行上述代码可以得到以下结果:
    -   Device mapping:
    -   /job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GRID K520, pci bus id: 0000:00:03.0
    -   /job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: GRID K520, pci bus id: 0000:00:04.0
    -   /job:localhost/replica:0/task:0/gpu:2 -> device: 2, name: GRID K520, pci bus id: 0000:00:05.0
    -   /job:localhost/replica:0/task:0/gpu:3 -> device: 3, name: GRID K520, pci bus id: 0000:00:06.0
    -   add: /job:localhost/replica:0/task:0/gpu:1
    -   b: /job:localhost/replica:0/task:0/cpu:0
    -   a: /job:localhost/replica:0/task:0/cpu:0
    -   [ 2\.  4\.  6.]
    -   '''
    -   import tensorflow as tf
    -   # 在CPU上运行tf.Variable
    -   a_cpu = tf.Variable(0, name="a_cpu")
    -   with tf.device('/gpu:0'):
    -   # 将tf.Variable强制放在GPU上。
    -   a_gpu = tf.Variable(0, name="a_gpu")
    -   sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
    -   sess.run(tf.initialize_all_variables())
    -   '''
    -   运行上面的程序将会报出以下错误:
    -   tensorflow.python.framework.errors.InvalidArgumentError: Cannot assign a device to node 'a_gpu': Could not satisfy explicit device specification '/device:GPU:0' because no supported kernel for GPU devices is available.
    -   Colocation Debug Info:
    -   Colocation group had the following types and devices:
    -   Identity: CPU
    -   Assign: CPU
    -   Variable: CPU
    -   [[Node: a_gpu = Variable[container="", dtype=DT_INT32, shape=[], shared_ name="", _device="/device:GPU:0"]()]]
    -   '''
    -   # define REGISTER_GPU_KERNELS(type)                                       \
    -   REGISTER_KERNEL_BUILDER(                                                 \
    -     Name("Variable").Device(DEVICE_GPU).TypeConstraint("dtype"),\
    -     VariableOp);                                                                 \
    -      …
    -   TF_CALL_GPU_NUMBER_TYPES(REGISTER_GPU_KERNELS);
    -   import tensorflow as tf
    -   a_cpu = tf.Variable(0, name="a_cpu")
    -   with tf.device('/gpu:0'):
    -   a_gpu = tf.Variable(0, name="a_gpu")
    -   # 通过allow_soft_placement参数自动将无法放在GPU上的操作放回CPU上。
    -   sess = tf.Session(config=tf.ConfigProto(
    -   allow_soft_placement=True, log_device_ placement=True))
    -   sess.run(tf.initialize_all_variables())
    -   '''
    -   运行上面这段程序可以得到下面的结果:
    -   Device mapping:
    -   /job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GRID K520, pci bus id: 0000:00:03.0
    -   /job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: GRID K520, pci bus id: 0000:00:04.0
    -   /job:localhost/replica:0/task:0/gpu:2 -> device: 2, name: GRID K520, pci bus id: 0000:00:05.0
    -   /job:localhost/replica:0/task:0/gpu:3 -> device: 3, name: GRID K520, pci bus id: 0000:00:06.0
    -   a_gpu: /job:localhost/replica:0/task:0/cpu:0
    -   a_gpu/read: /job:localhost/replica:0/task:0/cpu:0
    -   a_gpu/Assign: /job:localhost/replica:0/task:0/cpu:0
    -   init/NoOp_1: /job:localhost/replica:0/task:0/gpu:0
    -   a_cpu: /job:localhost/replica:0/task:0/cpu:0
    -   a_cpu/read: /job:localhost/replica:0/task:0/cpu:0
    -   a_cpu/Assign: /job:localhost/replica:0/task:0/cpu:0
    -   init/NoOp: /job:localhost/replica:0/task:0/gpu:0
    -   init: /job:localhost/replica:0/task:0/gpu:0
    -   a_gpu/initial_value: /job:localhost/replica:0/task:0/gpu:0
    -   a_cpu/initial_value: /job:localhost/replica:0/task:0/cpu:0
    -   从输出的日志中可以看到在生成变量a_gpu时,无法放到GPU上的运算被自动调整到了CPU上(比如a_gpu和a_gpu/read),而可以被GPU执行的命令(比如a_gpu/initial_value)依旧由GPU执行。
    -   '''
            -10.2 深度学习训练并行模式
            -10.3 多GPU并行
    -   # -*- coding: utf-8 -*-
    -   from datetime import datetime
    -   import os
    -   import time
    -   import tensorflow as tf
    -   import mnist_inference
    -   # 定义训练神经网络时需要用到的配置。这些配置与5.5节中定义的配置类似。
    -   BATCH_SIZE = 100
    -   LEARNING_RATE_BASE = 0.001
    -   LEARNING_RATE_DECAY = 0.99
    -   REGULARAZTION_RATE = 0.0001
    -   TRAINING_STEPS = 1000
    -   MOVING_AVERAGE_DECAY = 0.99
    -   N_GPU = 4
    -   # 定义日志和模型输出的路径。
    -   MODEL_SAVE_PATH = "/path/to/logs_and_models/"
    -   MODEL_NAME = "model.ckpt"
    -   # 定义数据存储的路径。因为需要为不同的GPU提供不同的训练数据,所以通过placerholder 的方式就需要手动准备多份数据。为了方便训练数据的获取过程,可以采用第7章中介绍的输
    -   # 入队列的方式从TFRecord中读取数据。于是在这里提供的数据文件路径为将MNIST训练数据 转化为TFRecords格式之后的路径。如何将MNIST数据转化为TFRecord格式在第7章中有
    -   # 详细介绍,这里不再赘述。
    -   DATA_PATH = "/path/to/data.tfrecords"
    -   # 定义输入队列得到训练数据,具体细节可以参考第7章。
    -   def get_input():
    -   filename_queue = tf.train.string_input_producer([DATA_PATH])
    -   reader = tf.TFRecordReader()
    -   _, serialized_example = reader.read(filename_queue)
    -   # 定义数据解析格式。
    -   features = tf.parse_single_example(
    -       serialized_example,
    -       features={
    -           'image_raw': tf.FixedLenFeature([], tf.string),
    -           'pixels': tf.FixedLenFeature([], tf.int64),
    -           'label': tf.FixedLenFeature([], tf.int64),
    -       })
    -   # 解析图片和标签信息。
    -   decoded_image = tf.decode_raw(features['image_raw'], tf.uint8)
    -   reshaped_image = tf.reshape(decoded_image, [784])
    -   retyped_image = tf.cast(reshaped_image, tf.float32)
    -   label = tf.cast(features['label'], tf.int32)
    -   # 定义输入队列并返回。
    -   min_after_dequeue = 10000
    -   capacity = min_after_dequeue + 3 * BATCH_SIZE
    -   return tf.train.shuffle_batch(
    -       [retyped_image, label],
    -       batch_size=BATCH_SIZE,
    -       capacity=capacity,
    -       min_after_dequeue=min_after_dequeue)
    -   # 定义损失函数。对于给定的训练数据、正则化损失计算规则和命名空间,计算在这个命名空间 下的总损失。之所以需要给定命名空间是因为不同的GPU上计算得出的正则化损失都会加入名为
    -   # loss的集合,如果不通过命名空间就会将不同GPU上的正则化损失都加进来。
    -   def get_loss(x, y_, regularizer, scope):
    -   # 沿用5.5节中定义的函数来计算神经网络的前向传播结果。
    -   y = mnist_inference.inference(x, regularizer)
    -   # 计算交叉熵损失。
    -   cross_entropy = tf.reduce_mean(
    -       tf.nn.sparse_softmax_cross_entropy_with_logits(y, y_))
    -   # 计算当前GPU上计算得到的正则化损失。
    -   regularization_loss = tf.add_n(tf.get_collection('losses', scope))
    -   # 计算最终的总损失。
    -   loss = cross_entropy + regularization_loss
    -   return loss
    -   # 计算每一个变量梯度的平均值。
    -   def average_gradients(tower_grads):
    -     average_grads = []
    -     # 枚举所有的变量和变量在不同GPU上计算得出的梯度。
    -     for grad_and_vars in zip(*tower_grads):
    -         # 计算所有GPU上的梯度平均值。
    -         grads = []
    -         for g, _ in grad_and_vars:
    -             expanded_g = tf.expand_dims(g, 0)
    -             grads.append(expanded_g)
    -         grad = tf.concat(0, grads)
    -         grad = tf.reduce_mean(grad, 0)
    -         v = grad_and_vars[0][1]
    -         grad_and_var = (grad, v)
    -         # 将变量和它的平均梯度对应起来。
    -         average_grads.append(grad_and_var)
    -   # 返回所有变量的平均梯度,这将被用于变量更新。
    -   return average_grads
    -   # 主训练过程。
    -   def main(argv=None):
    -   # 将简单的运算放在CPU上,只有神经网络的训练过程放在GPU上。
    -   with tf.Graph().as_default(), tf.device('/cpu:0'):
    -       # 获取训练batch。
    -       x, y_ = get_input()
    -       regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    -       # 定义训练轮数和指数衰减的学习率。
    -       global_step = tf.get_variable(
    -           'global_step', [], initializer=tf.constant_initializer(0),
    -            trainable=False)
    -       learning_rate = tf.train.exponential_decay(
    -           LEARNING_RATE_BASE, global_step, 60000 / BATCH_SIZE,
    -           LEARNING_ RATE_DECAY)
    -       # 定义优化方法。
    -       opt = tf.train.GradientDescentOptimizer(learning_rate)
    -       tower_grads = []
    -       # 将神经网络的优化过程跑在不同的GPU上。
    -       for i in range(N_GPU):
    -           # 将优化过程指定在一个GPU上。
    -           with tf.device('/gpu:%d' % i):
    -               with tf.name_scope('GPU_%d' % i) as scope:
    -                   cur_loss = get_loss(x, y_, regularizer, scope)
    -                   # 在第一次声明变量之后,将控制变量重用的参数设置为True。这样可以 让不同的GPU更新同一组参数。注意tf.name_scope函数并不会影响
    -                   # tf.get_ variable的命名空间。
    -                   tf.get_variable_scope().reuse_variables()
    -                   # 使用当前GPU计算所有变量的梯度。
    -                   grads = opt.compute_gradients(cur_loss)
    -                   tower_grads.append(grads)
    -       # 计算变量的平均梯度,并输出到TensorBoard日志中。
    -       grads = average_gradients(tower_grads)
    -       for grad, var in grads:
    -           if grad is not None:
    -               tf.histogram_summary(
    -                   'gradients_on_average/%s' % var.op.name, grad)
    -       # 使用平均梯度更新参数。
    -       apply_gradient_op = opt.apply_gradients(
    -           grads, global_step=global_ step)
    -       for var in tf.trainable_variables():
    -           tf.histogram_summary(var.op.name, var)
    -       # 计算变量的滑动平均值。
    -       variable_averages = tf.train.ExponentialMovingAverage(
    -           MOVING_AVERAGE_DECAY, global_step)
    -       variables_averages_op = variable_averages.apply(
    -           tf.trainable_variables())
    -       # 每一轮迭代需要更新变量的取值并更新变量的滑动平均值。
    -       train_op = tf.group(apply_gradient_op, variables_averages_op)
    -       saver = tf.train.Saver(tf.all_variables())
    -       summary_op = tf.merge_all_summaries()
    -       init = tf.initialize_all_variables()
    -       # 训练过程。
    -       with tf.Session(config=tf.ConfigProto(
    -           allow_soft_placement=True,
    -           log_device_placement=True)) as sess:
    -           # 初始化所有变量并启动队列。
    -           init.run()
    -           coord = tf.train.Coordinator()
    -           threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    -           summary_writer = tf.train.SummaryWriter(
    -               MODEL_SAVE_PATH, sess.graph)
    -           for step in range(TRAINING_STEPS):
    -               # 执行神经网络训练操作,并记录训练操作的运行时间。
    -               start_time = time.time()
    -               _, loss_value = sess.run([train_op, cur_loss])
    -               duration = time.time() - start_time
    -               # 每隔一段时间展示当前的训练进度,并统计训练速度。
    -               if step != 0 and step % 10 == 0:
    -                   # 计算使用过的训练数据个数。因为在每一次运行训练操作时,每一个GPU  都会使用一个batch的训练数据,所以总共用到的训练数据个数为
    -                   # batch大小×GPU个数。
    -                   num_examples_per_step = BATCH_SIZE * N_GPU
    -                   # num_examples_per_step为本次迭代使用到的训练数据个数,  duration为运行当前训练过程使用的时间,于是平均每秒可以处理的训
    -                   # 练数据个数为num_examples_per_step / duration。
    -                   examples_per_sec = num_examples_per_step / duration
    -                   # duration为运行当前训练过程使用的时间,因为在每一个训练过程中,  每一个GPU都会使用一个batch的训练数据,所以在单个batch上的训
    -                   # 练所需要时间为duration / GPU个数。
    -                   sec_per_batch = duration / N_GPU
    -                   # 输出训练信息。
    -                   format_str = ('step %d, loss = %.2f (%.1f examples/ '
    -                                   ' sec; %.3f sec/batch)')
    -                   print(format_str % (step, loss_value,
    -                                           examples_per_sec, sec_per_batch))
    -                   # 通过TensorBoard可视化训练过程。
    -                   summary = sess.run(summary_op)
    -                   summary_writer.add_summary(summary, step)
    -               # 每隔一段时间保存当前的模型。
    -               if step % 1000 == 0 or (step + 1) == TRAINING_STEPS:
    -                   checkpoint_path = os.path.join(
    -                       MODEL_SAVE_PATH, MODEL_ NAME)
    -                   saver.save(sess, checkpoint_path, global_step=step)
    -           coord.request_stop()
    -           coord.join(threads)
    -   if __name__ == '__main__':
    -   tf.app.run()
    -   '''
    -   在AWS的g2.8xlarge实例上运行上面这段程序可以得到类似下面的结果:
    -   step 10, loss = 71.90 (15292.3 examples/sec; 0.007 sec/batch)
    -   step 20, loss = 37.97 (18758.3 examples/sec; 0.005 sec/batch)
    -   step 30, loss = 9.54 (16313.3 examples/sec; 0.006 sec/batch)
    -   step 40, loss = 11.84 (14199.0 examples/sec; 0.007 sec/batch)
    -   ...
    -   step 980, loss = 0.66 (15034.7 examples/sec; 0.007 sec/batch)
    -   step 990, loss = 1.56 (16134.1 examples/sec; 0.006 sec/batch)
    -   '''
    -可视化得到的样例代码TensorFlow计算图,其中节点上的颜色代表了不同的设备,比如黑色代表CPU、白色代表第一个GPU,等等。从图10-5中可以看出,训练神经网络的主要过程被放到了GPU_0、GPU_1、GPU_2和GPU_3这4个模块中,而且每一个模块运行在一个GPU上。对比图10-5中的TensorFlow计算图可视化结果和图10-4中介绍的同步模式分布式深度学习训练流程图可以发现,这两个图的结构是非常接近的。
            - 10.4 分布式TensorFlow
                -书名页
    -10.4.1 分布式TensorFlow原理
    -   import tensorflow as tf
    -   c = tf.constant("Hello, distributed TensorFlow!")
    -   # 创建一个本地TensorFlow集群
    -   server = tf.train.Server.create_local_server()
    -   # 在集群上创建一个会话。
    -   sess = tf.Session(server.target)
    -   # 输出Hello, distributed TensorFlow!
    -   print sess.run(c)
    -   import tensorflow as tf
    -   c = tf.constant("Hello from server1!")
    -   # 生成一个有两个任务的集群,一个任务跑在本地2222端口,另外一个跑在本地2223端口。
    -   cluster = tf.train.ClusterSpec(
    -   {"local": ["localhost:2222", "localhost: 2223"]})
    -   # 通过上面生成的集群配置生成Server,并通过job_name和task_index指定当前所启动 的任务。因为该任务是第一个任务,所以task_index为0。
    -   server = tf.train.Server(cluster, job_name="local", task_index=0)
    -   # 通过server.target生成会话来使用TensorFlow集群中的资源。通过设置 log_device_placement可以看到执行每一个操作的任务。
    -   sess = tf.Session(
    -   server.target, config=tf.ConfigProto(log_device_placement=True))
    -   print sess.run(c)
    -   server.join()
    -   import tensorflow as tf
    -   c = tf.constant("Hello from server2!")
    -   # 和第一个程序一样的集群配置。集群中的每一个任务需要采用相同的配置。
    -   cluster = tf.train.ClusterSpec(
    -   {"local": ["localhost:2222", "localhost: 2223"]})
    -   # 指定task_index为1,所以这个程序将在localhost:2223启动服务。
    -   server = tf.train.Server(cluster, job_name="local", task_index=1)
    -   # 剩下的代码都和第一个任务的代码一致。
    -   ...
    -   I tensorflow/core/distributed_runtime/rpc/grpc_channel.cc:206] Initialize HostPortsGrpcChannelCache for job local -> {localhost:2222, localhost:2223}
    -   I tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc:202] Started server with target: grpc://localhost:2222
    -   E1123 08:26:06.824503525   12232 tcp_client_posix.c:173]     failed to connect to 'ipv4:127.0.0.1:2223': socket error: connection refused
    -   E1123 08:26:08.825022513   12232 tcp_client_posix.c:173]     failed to connect to 'ipv4:127.0.0.1:2223': socket error: connection refused
    -   I tensorflow/core/common_runtime/simple_placer.cc:818] Const: /job:local/ replica:0/task:0/cpu:0
    -   Const: /job:local/replica:0/task:0/cpu:0
    -   Hello from server1!
    -   I tensorflow/core/distributed_runtime/rpc/grpc_channel.cc:206] Initialize HostPortsGrpcChannelCache for job local -> {localhost:2222, localhost:2223}
    -   I tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc:202] Started server with target: grpc://localhost:2223
    -   Const: /job:local/replica:0/task:0/cpu:0
    -   I tensorflow/core/common_runtime/simple_placer.cc:818] Const: /job:local/ replica:0/task:0/cpu:0
    -   Hello from server2!
    -   with tf.device("/job:local/task:1"):
    -   c = tf.constant("Hello from server2!")
    -   tf.train.ClusterSpec({
    -   "worker": [
    -       "tf-worker0:2222",
    -       "tf-worker1:2222",
    -       "tf-worker2:2222"
    -   ],
    -   "ps": [
    -       "tf-ps0:2222",
    -       "tf-ps1:2222"
    -   ]}) [(7)](part0017_split_005.html#ch7)
                -书名页
    -10.4.2 分布式TensorFlow模型训练
    -   # -*- coding: utf-8 -*-
    -   import time
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   import mnist_inference
    -   # 和5.5节中类似的配置神经网络的设置。
    -   BATCH_SIZE = 100
    -   LEARNING_RATE_BASE = 0.01
    -   LEARNING_RATE_DECAY = 0.99
    -   REGULARAZTION_RATE = 0.0001
    -   TRAINING_STEPS = 10000
    -   # 模型保存的路径。
    -   MODEL_SAVE_PATH = "/path/to/model"
    -   # MNIST数据路径。
    -   DATA_PATH = "/path/to/data"
    -   # 通过flags指定运行的参数。在10.4.1小节中对于不同的任务(task)给出了不同的程序, 但这不是一种可扩展的方式。在这一小节中将使用运行程序时给出的参数来配置在不同
    -   # 任务中运行的程序。
    -   FLAGS = tf.app.flags.FLAGS
    -   # 指定当前运行的是参数服务器还是计算服务器。参数服务器只负责TensorFlow中变量的维护 和管理,计算服务器负责每一轮迭代时运行反向传播过程。
    -   tf.app.flags.DEFINE_string('job_name', 'worker', ' "ps" or "worker" ')
    -   # 指定集群中的参数服务器地址。
    -   tf.app.flags.DEFINE_string(
    -   'ps_hosts', ' tf-ps0:2222,tf-ps1:1111',
    -   'Comma-separated list of hostname:port for the parameter server jobs. '
    -   'e.g. "tf-ps0:2222,tf-ps1:1111" ')
    -   # 指定集群中的计算服务器地址。
    -   tf.app.flags.DEFINE_string(
    -   'worker_hosts', ' tf-worker0:2222,tf-worker1:1111',
    -   'Comma-separated list of hostname:port for the worker jobs. '
    -   'e.g. "tf-worker0:2222,tf-worker1:1111" ')
    -   # 指定当前程序的任务ID。TensorFlow会自动根据参数服务器/计算服务器列表中的端口号 来启动服务。注意参数服务器和计算服务器的编号都是从0开始的。
    -   tf.app.flags.DEFINE_integer(
    -   'task_id', 0, 'Task ID of the worker/replica running the training.')
    -   # 定义TensorFlow的计算图,并返回每一轮迭代时需要运行的操作。这个过程和5.5节中的主 函数基本一致,但为了使处理分布式计算的部分更加突出,本小节将此过程整理为一个函数。
    -   def build_model(x, y_, is_chief):
    -      regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    -      # 通过和5.5节给出的mnist_inference.py代码计算神经网络前向传播的结果。
    -      y = mnist_inference.inference(x, regularizer)
    -      global_step = tf.Variable(0, trainable=False)
    -      # 计算损失函数并定义反向传播过程。
    -      cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
    -       y, tf.argmax(y_, 1))
    -      cross_entropy_mean = tf.reduce_mean(cross_entropy)
    -      loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    -      learning_rate = tf.train.exponential_decay(
    -      LEARNING_RATE_BASE, global_step, 60000 / BATCH_SIZE,
    -       LEARNING_RATE_ DECAY)
    -      # 定义每一轮迭代需要运行的操作。
    -      train_op = tf.train.GradientDescentOptimizer(learning_rate)\
    -                  .minimize(loss, global_step=global_step)
    -      return global_step, loss, train_op
    -   # 训练分布式深度学习模型的主过程。
    -   def main(argv=None):
    -      # 解析flags并通过tf.train.ClusterSpec配置TensorFlow集群。
    -      ps_hosts = FLAGS.ps_hosts.split(',')
    -      worker_hosts = FLAGS.worker_hosts.split(',')
    -      cluster = tf.train.ClusterSpec({"ps": ps_hosts, "worker": worker_hosts})
    -      # 通过ClusterSpec以及当前任务创建Server。
    -      server = tf.train.Server(
    -      cluster, job_name=FLAGS.job_name, task_index=FLAGS.task_id)
    -      # 参数服务器只需要管理TensorFlow中的变量,不需要执行训练的过程。server.join() 会一直停在这条语句上。
    -      if FLAGS.job_name == 'ps':
    -      server.join()
    -      # 定义计算服务器需要运行的操作。在所有的计算服务器中有一个是主计算服务器,它除了负责 计算反向传播的结果,它还负责输出日志和保存模型。
    -      is_chief = (FLAGS.task_id == 0)
    -      mnist = input_data.read_data_sets(DATA_PATH, one_hot=True)
    -      # 通过tf.train.replica_device_setter函数来指定执行每一个运算的设备。 tf.train.replica_device_setter函数会自动将所有的参数分配到参数服务器上,而
    -      # 计算分配到当前的计算服务器上。图10-9展示了通过TensorBoard可视化得到的第一个计 算服务器上运算分配的结果。
    -      with tf.device(tf.train.replica_device_setter(
    -          worker_device="/job:worker/task:%d" % FLAGS.task_id,
    -           cluster=cluster)):
    -      x = tf.placeholder(
    -           tf.float32, [None, mnist_inference.INPUT_NODE],
    -           name='x-input')
    -      y_ = tf.placeholder(
    -           tf.float32, [None, mnist_inference.OUTPUT_NODE],
    -           name='y-input')
    -       # 定义训练模型需要运行的操作。
    -      global_step, loss, train_op = build_model(x, y_)
    -       # 定义用于保存模型的saver。
    -      saver = tf.train.Saver()
    -       # 定义日志输出操作。
    -      summary_op = tf.merge_all_summaries()
    -       # 定义变量初始化操作。
    -      init_op = tf.initialize_all_variables()
    -       # 通过tf.train.Supervisor管理训练深度学习模型的通用功能。 tf.train. Supervisor能统一管理队列操作、模型保存、日志输出以及会话的生成。
    -      sv = tf.train.Supervisor(
    -          is_chief=is_chief,           # 定义当前计算服务器是否为主计算服务器,只有 主计算服务器会保存模型以及输出日志。
    -        logdir=MODEL_SAVE_PATH,        # 指定保存模型和输出日志的地址。
    -        init_op=init_op,               # 指定初始化操作。
    -        summary_op=summary_op,         # 指定日志生成操作。
    -        saver = saver,                 # 指定用于保存模型的saver。
    -        global_step=global_step,       # 指定当前迭代的轮数,这个会用于生成保存模 型文件的文件名。
    -        save_model_secs=60,            # 指定保存模型的时间间隔。
    -        save_summaries_secs=60)        # 指定日志输出的时间间隔。
    -      sess_config = tf.ConfigProto(allow_soft_placement=True,
    -                                          log_device_placement=False)
    -       # 通过tf.train.Supervisor生成会话。
    -      sess = sv.prepare_or_wait_for_session(
    -            server.target, config=sess_config)
    -      step = 0
    -      start_time = time.time()
    -       # 执行迭代过程。在迭代过程中tf.train.Supervisor会帮助输出日志并保存模型,  所以不需要直接调用这些过程。
    -      while not sv.should_stop():
    -          xs, ys = mnist.train.next_batch(BATCH_SIZE)
    -          _, loss_value, global_step_value = sess.run(
    -                [train_op, loss, global_step], feed_dict={x: xs, y_: ys})
    -          if global_step_value >= TRAINING_STEPS: break
    -            # 每隔一段时间输出训练信息。
    -          if step > 0 and step % 100 == 0:
    -              duration = time.time() - start_time
    -                 # 不同的计算服务器都会更新全局的训练轮数,所以这里使用 global_step_value可以直接得到在训练中使用过的batch的总数。
    -              sec_per_batch = duration / global_step_value
    -              format_str = ("After %d training steps (%d global steps), "
    -                                 "loss on training batch is %g.  "
    -                                 "(%.3f sec/batch)")
    -              print(format_str % (step, global_step_value,
    -                                         loss_value, sec_per_batch))
    -          step += 1
    -      sv.stop()
    -   if __name__ == "__main__":
    -      tf.app.run()
    -   python dist_tf_mnist_async.py \
    -   --job_name='ps' \
    -   --task_id=0 \
    -   --ps_hosts='tf-ps0:2222' \
    -   --worker_hosts='tf-worker0:2222,tf-worker1:2222'
    -   python dist_tf_mnist_async.py \
    -   --job_name='worker' \
    -   --task_id=0 \
    -   --ps_hosts='tf-ps0:2222' \
    -   --worker_hosts='tf-worker0:2222,tf-worker1:2222'
    -   python dist_tf_mnist_async.py \
    -   --job_name='worker' \
    -   --task_id=1 \
    -   --ps_hosts='tf-ps0:2222' \
    -   --worker_hosts='tf-worker0:2222,tf-worker1:2222'
    -   E1201 01:26:04.166203632   21402 tcp_client_posix.c:173]     failed to connect to 'ipv4:tf-worker1:2222': socket error: connection refused
    -   After 100 training steps (100 global steps), loss on training batch is 0.302718\.  (0.039 sec/batch)
    -   After 200 training steps (200 global steps), loss on training batch is 0.269476\.  (0.037 sec/batch)
    -   After 300 training steps (300 global steps), loss on training batch is 0.286755\.  (0.037 sec/batch)
    -   After 400 training steps (463 global steps), loss on training batch is 0.349983\.  (0.033 sec/batch)
    -   After 500 training steps (666 global steps), loss on training batch is 0.229955\.  (0.029 sec/batch)
    -   After 600 training steps (873 global steps), loss on training batch is 0.245588\.  (0.027 sec/batch)
    -   After 100 training steps (537 global steps), loss on training batch is 0.223165\.  (0.007 sec/batch)
    -   After 200 training steps (732 global steps), loss on training batch is 0.186126\.  (0.010 sec/batch)
    -   After 300 training steps (925 global steps), loss on training batch is 0.228191\.  (0.012 sec/batch)
    -   # -*- coding: utf-8 -*-
    -   import time
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   import mnist_inference
    -   BATCH_SIZE = 100
    -   LEARNING_RATE_BASE = 0.8
    -   LEARNING_RATE_DECAY = 0.99
    -   REGULARAZTION_RATE = 0.0001
    -   TRAINING_STEPS = 10000
    -   MODEL_SAVE_PATH = "/path/to/model"
    -   DATA_PATH = "/path/to/data"
    -   # 和异步模式类似的设置flags。
    -   FLAGS = tf.app.flags.FLAGS
    -   tf.app.flags.DEFINE_string('job_name', 'worker', ' "ps" or "worker" ')
    -   tf.app.flags.DEFINE_string(
    -   'ps_hosts', ' tf-ps0:2222,tf-ps1:1111',
    -      'Comma-separated list of hostname:port for the parameter server jobs. '
    -   'e.g. "tf-ps0:2222,tf-ps1:1111" ')
    -   tf.app.flags.DEFINE_string(
    -   'worker_hosts', ' tf-worker0:2222,tf-worker1:1111',
    -   'Comma-separated list of hostname:port for the worker jobs. '
    -   'e.g. "tf-worker0:2222,tf-worker1:1111" ')
    -   tf.app.flags.DEFINE_integer(
    -   'task_id', 0, 'Task ID of the worker/replica running the training.')
    -   # 和异步模式类似地定义TensorFlow的计算图。唯一的区别在于使用 tf.train.SyncReplicasOptimizer函数处理同步更新。
    -   def build_model(x, y_, n_workers, is_chief):
    -      regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    -      y = mnist_inference.inference(x, regularizer)
    -      global_step = tf.Variable(0, trainable=False)
    -      variable_averages = tf.train.ExponentialMovingAverage(
    -       MOVING_AVERAGE_ DECAY, global_step)
    -      variables_averages_op = variable_averages.apply(tf.trainable_variables())
    -      cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
    -       y, tf.argmax(y_, 1))
    -      cross_entropy_mean = tf.reduce_mean(cross_entropy)
    -      loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    -      learning_rate = tf.train.exponential_decay(
    -      LEARNING_RATE_BASE, global_step, 60000 / BATCH_SIZE,
    -       LEARNING_RATE_ DECAY)
    -      # 通过tf.train.SyncReplicasOptimizer函数实现同步更新。
    -      opt = tf.train.SyncReplicasOptimizer(
    -          # 定义基础的优化方法。
    -          tf.train.GradientDescentOptimizer(learning_rate),
    -          # 定义每一轮更新需要多少个计算服务器得出的梯度。
    -          replicas_to_aggregate=n_workers,
    -          # 指定总共有多少个计算服务器。
    -          total_num_replicas=n_workers,
    -          # 指定当前计算服务器的编号。
    -          replica_id=FLAGS.task_id)
    -      train_op = opt.minimize(loss, global_step=global_step)
    -      return global_step, loss, train_op, opt
    -   def main(argv=None):
    -      # 和异步模式类似地创建TensorFlow集群。
    -      ps_hosts = FLAGS.ps_hosts.split(',')
    -      worker_hosts = FLAGS.worker_hosts.split(',')
    -      n_workers = len(worker_hosts)
    -      cluster = tf.train.ClusterSpec({"ps": ps_hosts, "worker": worker_hosts})
    -      server = tf.train.Server(
    -      cluster, job_name = FLAGS.job_name, task_index=FLAGS.task_id)
    -      if FLAGS.job_name == 'ps':
    -      server.join()
    -      is_chief = (FLAGS.task_id == 0)
    -      mnist = input_data.read_data_sets(DATA_PATH, one_hot=True)
    -      with tf.device(tf.train.replica_device_setter(
    -          worker_device="/job:worker/task:%d" % FLAGS.task_id,
    -            cluster=cluster)):
    -      x = tf.placeholder(
    -           tf.float32, [None, mnist_inference.INPUT_NODE],
    -           name='x-input')
    -      y_ = tf.placeholder(
    -           tf.float32, [None, mnist_inference.OUTPUT_NODE],
    -           name='y-input')
    -      global_step, loss, train_op, opt = build_model(
    -           x, y_, n_workers, is_chief)
    -      saver = tf.train.Saver()
    -      summary_op = tf.merge_all_summaries()
    -      init_op = tf.initialize_all_variables()
    -       # 在同步模式下,主计算服务器需要协调不同计算服务器计算得到的参数梯度并最终更新 参数。这需要主计算服务器完成一些额外的初始化工作。
    -      if is_chief:
    -            # 定义协调不同计算服务器的队列并定义初始化操作。
    -          chief_queue_runner = opt.get_chief_queue_runner()
    -          init_tokens_op = opt.get_init_tokens_op(0)
    -       # 和异步模式类似的声明tf.train.Supervisor。
    -      sv = tf.train.Supervisor(is_chief=is_chief,
    -                               logdir=MODEL_SAVE_PATH,
    -                               init_op=init_op,
    -                               summary_op=summary_op,
    -                               saver=saver,
    -                               global_step=global_step,
    -                               save_model_secs=60,
    -                               save_summaries_secs=60)
    -      sess_config = tf.ConfigProto(allow_soft_placement=True,
    -                                          log_device_placement=False)
    -      sess = sv.prepare_or_wait_for_session(
    -           server.target, config=sess_config)
    -       # 在开始训练模型之前,主计算服务器需要启动协调同步更新的队列并执行初始化操作。
    -      if is_chief:
    -          sv.start_queue_runners(sess, [chief_queue_runner])
    -          sess.run(init_tokens_op)
    -       # 和异步模式类似的运行迭代的训练过程。
    -      step = 0
    -      start_time = time.time()
    -      while not sv.should_stop():
    -          xs, ys = mnist.train.next_batch(BATCH_SIZE)
    -          _, loss_value, global_step_value = sess.run(
    -                [train_op, loss, global_step], feed_dict={x: xs, y_: ys})
    -          if global_step_value >= TRAINING_STEPS: break
    -          if step > 0 and step % 100 == 0:
    -              duration = time.time() - start_time
    -              sec_per_batch = duration / (global_step_value * n_workers)
    -              format_str = ("After %d training steps (%d global steps), "
    -                                 "loss on training batch is %g.  "
    -                                 "(%.3f sec/batch)")
    -              print(format_str % (step, global_step_value,
    -                                         loss_value, sec_per_batch))
    -          step += 1
    -      sv.stop()
    -   if __name__ == "__main__":
    -      tf.app.run()
    -   E1201 01:26:04.166203632   21402 tcp_client_posix.c:173]     failed to connect to 'ipv4:10.57.60.76:2222': socket error: connection refused
    -   After 100 training steps (100 global steps), loss on training batch is 1.88782\.  (0.176 sec/batch)
    -   After 200 training steps (200 global steps), loss on training batch is 0.834916\.  (0.101 sec/batch)
    -   …
    -   After 800 training steps (800 global steps), loss on training batch is 0.524181\.  (0.045 sec/batch)
    -   After 900 training steps (900 global steps), loss on training batch is 0.384861\.  (0.042 sec/batch)
    -   After 100 training steps (100 global steps), loss on training batch is 1.88782\.  (0.028 sec/batch)
    -   After 200 training steps (200 global steps), loss on training batch is 0.834916\.  (0.027 sec/batch)
    -   …
    -   After 800 training steps (800 global steps), loss on training batch is 0.474765\.  (0.026 sec/batch)
    -   After 900 training steps (900 global steps), loss on training batch is 0.420769\.  (0.026 sec/batch)
                -书名页
    -10.4.3 使用Caicloud运行分布式TensorFlow
    -,可以发现TensorFlow只实现了相当于Hadoop中MapReduce的计算框架,而没有提供类似Yarn的集群管理工具以及HDFS的存储系统。为了降低分布式TensorFlow的使用门槛,才云科技(Caicloud.io)基于Kubernetes [(9)](part0017_split_005.html#ch9)
    -容器云平台提供了一个分布式TensorFlow平台TensorFlow as a Service(TaaS) [(10)](part0017_split_005.html#ch10)
    -。本节中将大致介绍如何使用Caicloud提供的TaaS平台运行分布式TensorFlow。
    -   import caicloud_dist_tensorflow_base as caicloud
    -   class MyDistTfModel(caicloud.CaicloudDistTensorflowBase):
    -   """基于自身业务来定义训练模型、执行训练操作等"""
    -。
    -   import tensorflow as tf
    -   from tensorflow.examples.tutorials.mnist import input_data
    -   import caicloud_dist_tensorflow_base as caicloud [(12)](part0017_split_005.html#ch12)
    -   class CaicloudDistMnist(caicloud.CaicloudDistTensorflowBase):
    -      # 定义神经网络前向传播的过程。
    -      def _inference(self, images):
    -      w = tf.Variable(tf.zeros([784, 10]), name='weights')
    -      tf.summary.histogram("weights", w)
    -      b = tf.Variable(tf.zeros([10]), name='bias')
    -      tf.summary.histogram("bias", b)
    -      predictions = tf.matmul(images, w) + b
    -      return predictions
    -      # 定义优化函数。在同步模式下需要使用SyncReplicasOptimizerV2来同步不同worker。
    -      def _create_optimizer(self, sync, num_replicas):
    -      optimizer = tf.train.AdagradOptimizer(0.01);
    -      if sync:
    -          num_workers = num_replicas
    -          optimizer = tf.train.SyncReplicasOptimizerV2(
    -              optimizer,
    -              replicas_to_aggregate=num_workers,
    -              total_num_replicas=num_workers,
    -              name="mnist_sync_replicas")
    -      return optimizer
    -      # build_model函数中,global_step参数是全局的训练轮数,在定义优化函数时需要将训 练轮数作为参数传入,这样global_step可以通过优化器自动维护。is_chief参数给出了
    -      # 当前节点是否为主计算节点。sync参数给出了是否使用同步模式。当sync为True时模型 需要采用同步模式更新,否则使用异步模式。num_replicas参数给出了该TensorFlow集
    -      # 群中计算节点的个数。build_model函数需要返回一个tensorflow.train.Optimizer 对象,TaaS平台将自动使用该对象来完成同步模式下初始化的工作。
    -      def build_model(self, global_step, is_chief, sync, num_replicas):
    -       # 定义当前worker的训练轮数,该变量可以用来输出训练信息。
    -      self._step = 0
    -      # 加载MNIST数据,数据存放的地址需要为Caicloud提供的存储路径。
    -      mnist = input_data.read_data_sets(
    -            "/caicloud/dist-tf/base/examples/mnist/data", one_hot=True)
    -      self._mnist = mnist
    -      # 定义神经网络的输入和模型的前向传播。
    -      input_images = tf.placeholder(
    -           tf.float32, [None, 784], name='images')
    -      self._input_images = input_images
    -      predictions = self._inference(input_images)
    -      # 定义损失函数。
    -      labels = tf.placeholder(tf.float32, [None, 10], name='labels')
    -      self._labels = labels
    -      cross_entropy = tf.reduce_mean(
    -            tf.nn.softmax_cross_entropy_with_logits(predictions, labels))
    -      self._loss = tf.reduce_mean(
    -            cross_entropy, name='cross_entropy_ mean')
    -      # 定义优化函数。在调用优化函数时,我们需要将global_step传入优化函数,否则系统 将无法获取全局的训练轮数。
    -      optimizer = self._create_optimizer(sync, num_replicas)
    -      train_op = optimizer.minimize(
    -           cross_entropy, global_step=global_ step)
    -      self._train_op = train_op
    -      # 定义计算正确率的方法。
    -      correct_prediction = tf.equal(tf.argmax(predictions, 1),
    -                                           tf.argmax (labels, 1))
    -      accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    -      self._accuracy = accuracy
    -      # 返回优化函数。
    -      return optimizer
    -      # Caicloud TaaS平台在生成TensorFlow会话(Session)之后会自动地执行默认的初 始化操作,例如参数初始化、同步模式更新队列初始化等。但如果用户有其他需要在开始模
    -      # 型训练之前完成的操作,例如模型预加载,则可以通过定义get_init_fn函数来完成。 get_init_fn函数的参数checkpoint_path提供了用于模型预加载的checkpoint文件
    -      # 地址或checkpoint文件所在目录的路径。get_init_fn函数的返回为一个函数,该函数 必须接收一个参数,即一个可用的会话(Session)。该函数将在启动模型训练之前被调用。
    -      # 以下代码展示了如何通过该函数进行模型预加载。
    -      def get_init_fn(self, checkpoint_path):
    -      # 获取模型文件地址。
    -      if tf.gfile.IsDirectory(checkpoint_path):
    -          checkpoint_path = tf.train.latest_checkpoint(checkpoint_path)
    -      else:
    -          checkpoint_path = checkpoint_path
    -      print('warm-start from checkpoint {0}'.format(checkpoint_path))
    -      # 模型预加载。
    -      saver = tf.train.Saver(tf.trainable_variables())
    -      def InitAssignFn(sess):
    -          saver.restore(sess, checkpoint_path)
    -      # 返回执行模型预加载的函数。
    -      return InitAssignFn
    -      # Caicloud TaaS平台会自动地循环调用train函数来训练深度学习模型。train函数中,  用户只需要定义每一轮训练中需要执行的步骤。训练的步骤可以包括调用优化函数以及计算滑
    -      # 动平均等。train函数需要返回一个布尔类型,表示当前训练是否需要结束。这样可以支持当 正确率比较稳定之后提前结束训练。
    -      def train(self, session, global_step, is_chief):
    -      # 执行模型训练步骤并记录时间。
    -      start_time = time.time()
    -      batch_xs, batch_ys = self._mnist.train.next_batch(100)
    -      feed_dict = {self._input_images: batch_xs, self._labels: batch_ys}
    -      _, loss_value, np_global_step = session.run(
    -          [self._train_op, self._loss, global_step],
    -          feed_dict=feed_dict)
    -      self._step += 1
    -      duration = time.time() - start_time
    -      # 每隔一段时间输出训练信息。
    -      if self._step % 50 == 0:
    -          print('Step %d: loss = %.2f (%.3f sec), global step: %d.' % (
    -              self._step, loss_value, duration, np_global_step))
    -      if self._step % 1000 == 0:
    -          print("Accuaracy on Validation Data: %.3f" % session.run(
    -              self._accuracy, feed_dict={
    -                  self._input_images: self._mnist.validation.images,
    -                  self._labels: self._mnist.validation.labels}))
    -      return False
    -      # 在模型训练成功结束后希望能够计算最终训练得到的模型在MNIST测试数据集上的正确率。 这个过程可以通过定义after_train函数来实现。类似的,用户也可以在after_train
    -      # 函数中保存最终的模型。
    -      def after_train(self, session, is_chief):
    -      print("train done.")
    -      print("Accuracy on Test Data: %.3f" % session.run(
    -          self._accuracy, feed_dict={
    -              self._input_images: self._mnist.test.images,
    -              self._labels: self._mnist.test.labels}))
            - 小结
    - 数字出自谷歌官方技术博客https://research.googleblog.com/2016/04/announcing-tensorflow-08-now-with.html。
    - 如何安装支持GPU的TensorFlow环境可以参考第2章。
    - TensorFlow kernel在Github的https://github.com/tensorflow/tensorflow/tree/master/tensorflow/core/kernels目录下。
    - 不同的算法实现会有略微的区别。TensorFlow也支持更加灵活的同步更新方式使计算不会因为某个设备的故障而被卡住。而且在同步模式下,TensorFlow会保证没有设备能使用陈旧的梯度更新模型中的参数。
    - TensorBoard在第9章中有详细介绍。
    - 具体结果可以参考谷歌官方技术博客:https://research.googleblog.com/2016/04/announcing-tensorflow- 08-now-with.html。
    - 注意这里给出的tf-worker(i)和tf-ps(i)都是服务器地址。
    - 更多关于Hadoop的介绍可以参考其官方网站:http://hadoop.apache.org/。
    - 更多关于Kubernetes的介绍可以参考其官方网站:http://kubernetes.io/。
    - TaaS公有云服务测试版将于2017年3月底正式上线。
    - Caicloud提供的TaaS平台只支持TensorFlow 0.12.0及以上版本。
    - 在Caicloud提供的开发环境中可以加载caicloud_dist_tensorflow_base模块。Caicloud同时也提供了用于开发的caicloud_dist_tensorflow_base源代码及pip安装包,感兴趣的读者可以参考才云科技官网caicloud.io。
Copyright & copy 7dtime.com 2014-2018 all right reserved,powered by Gitbook该文件修订时间: 2018-09-02 18:17:12

results matching ""

    No results matching ""