TensorFlow 介绍(更新中)

    Machine Learning

TensorFlow 是 Google 的一个开源深度学习框架


安装 TensorFlow

可以使用 pip 安装(见这里),也可以用 conda ,这里选用 conda 的安装方式。至于 conda 是什么?如何安装和配置?请参考安装和配置 Anaconda

# 最左边的 (ai-dl) 表示当前处于虚拟开发环境 ai-dl 中
(ai-dl) $ conda install -c conda-forge tensorflow

# 查看当前的虚拟开发环境中存在的 tensorflow 以及其版本
(ai-dl) $ conda list | grep -ir "tensorflow"
(standard input):tensorflow       1.10.0        py35_0    conda-forge

测试 TensorFlow ,如果安装正确,Console 会打印出 “Hello, world!”

### tensorflow_test.py ###

import tensorflow as tf
# Create TensorFlow object called tensor
hello_constant = tf.constant('Hello World!')
with tf.Session() as sess:
    # Run the tf.constant operation in the session
    output = sess.run(hello_constant)
    print(output)

PS:
有可能会遇到以下输出信息,这是因为你的 CPU 有线性加速功能 AVX2 FMA 而当前安装的 TensorFlow 不能使用它们(GPU 才能发挥 TensorFlow 的威力,所以 TensorFlow 不太支持 CPU),具体可以参见这里

(ai-dl) $ python tensorflow_test.py
2018-09-21 23:20:36.754440: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
b'Hello World!'

常用函数

  • tf.placeholder

    # TensorFlow uses arrays rather than tuples. It converts tuples to arrays. Therefore [] and () are equivalent.
    # Placeholder with [] shape takes a single scalar value directly.
    w = tf.placeholder(dtype=tf.int32, shape=(), name="foo0")
    x = tf.placeholder(dtype=tf.int32, shape=[], name="foo1")
    
    # Placeholder with [None] shape takes a 1-dimensional array
    y = tf.placeholder(dtype=tf.int32, shape=[None], name="foo2")
    
    # Placeholder with None shape can take in any value while computation takes place.
    z = tf.placeholder(dtype=tf.int32, shape=None, name="foo3")
    
    # Example
    # 创建 rank 4(维度为 4)的 Tensor
    # None 代表该维度可以是任意的数值,在深度学习神经网络中该维度通常代表 batch 的数量 - batch 的数量是超参数 batch size 决定的,因此是可变不固定的  
    inputs_real_img = tf.placeholder(tf.float32, [None, image_width, image_height, image_channels])
    
    # 创建标量(scalar)的 Tensor
    learning_rate = tf.placeholder(tf.float32, [])
    
  • tf.reshape
    MNIST 数据集是由 28px * 28px 单通道图片组成。tf.reshape 函数把 28px * 28px 的矩阵转换成了 784px * 1px 的单行向量 x。tf.reshape() 中 -1 的解释参见官方文档这篇博客
    简单来说就是 -1 这个位置的维度由 reshape() 函数自动计算出,到底是多少取决于其他维度的数据,只要所有元素的总和等于前面 x 的元素总和即可 - 可以看到,张量(tensor)x 中一共有 28 * 28 * 1 = 784 个元素,而 n_input = 784 ,所以 -1 这个位置的维度值为 28 * 28 * 1 / n_input = 784 /784 = 1,进而 x_flat 的维度就是 [1, 784]
    更多关于 Shape 的知识细节可以从这篇延伸阅读开始:
    Understanding Tensorflow’s tensors shape: static and dynamic

    import tensorflow as tf
    
    n_input = 784  # MNIST data input (img shape: 28*28)
    n_classes = 10  # MNIST total classes (0-9 digits)
    
    # tf Graph input
    x = tf.placeholder("float", [None, 28, 28, 1])
    y = tf.placeholder("float", [None, n_classes])
    
    x_flat = tf.reshape(x, [-1, n_input])
    
  • tf.nn.dropouttf.layers.dropout 的区别
    两者都用于是给神经网络的隐藏层(Hidden Layers)添加 dropout 层的,它们之间的区别仅仅在于接收的参数不同,导致双方对 dropout 层有着不一样的控制能力。具体可参见 what’s the difference between tf.nn.dropout and tf.layers.dropout


基础神经网络 - Vanilla

Vanilla 前馈神经网络(Feed Forward Neural Network)
TODO


卷积神经网络 - CNN

卷积神经网络(Convolutional Neural Network)
TODO


循环神经网络 - RNN

循环神经网络(Recurrent Neural Network)
TODO


生成对抗神经网络 - GAN

生成对抗网络(Generative Adversarial Network)

def model_inputs(real_dim, z_dim):
    # tf.placeholder 的 shape 参数里值为 None 的维度代表该维度可以是任何值(整数)
    # 此处该维度是用来放置 Batch 数量的,根据 Batch Size 不同的值,Batch 的数量也会不同,所以这是一个可变的维度   
    inputs_real = tf.placeholder(tf.float32, shape=(None, real_dim), name="input_real")
    inputs_z = tf.placeholder(tf.float32, shape=(None, z_dim), name="input_z")

    return inputs_real, inputs_z

神经网络示例

### tensorflow_demo.py ###
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 使用 TensorFlow 提供的 MNIST 数据集,其中对数据的分批和 One-Hot 编码已经完成
mnist = input_data.read_data_sets(".", one_hot=True, reshape=False)

# 超参数 Parameters
learning_rate = 0.001
training_epochs = 20
batch_size = 128  # 如果没有足够内存,可以降低 batch size
display_step = 1

n_input = 784  # MNIST data input (img shape: 28*28 = 784)
n_classes = 10  # MNIST total classes (0-9 digits)
n_hidden_layer = 256 # 隐藏层的节点数(本例以一个隐藏层为例,给该层设置了 256 个节点「nodes」)


# 设置层权重(Weights)和偏差(Bias)的储存
weights = {
    'hidden_layer': tf.Variable(tf.random_normal([n_input, n_hidden_layer])),
    'out': tf.Variable(tf.random_normal([n_hidden_layer, n_classes]))
}
biases = {
    'hidden_layer': tf.Variable(tf.random_normal([n_hidden_layer])),
    'out': tf.Variable(tf.random_normal([n_classes]))
}


# tf Graph input - 输入层设置
x = tf.placeholder("float", [None, 28, 28, 1])
y = tf.placeholder("float", [None, n_classes])
x_flat = tf.reshape(x, [-1, n_input])


# Hidden layer with RELU activation
# ReLU作为隐藏层激活函数
layer_1 = tf.add(tf.matmul(x_flat, weights['hidden_layer']),\
    biases['hidden_layer'])
layer_1 = tf.nn.relu(layer_1)
# Output layer with linear activation
# 输出层的线性激活函数
logits = tf.add(tf.matmul(layer_1, weights['out']), biases['out'])


# Define loss and optimizer
# 定义误差值和优化器
cost = tf.reduce_mean(\
    tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)\
    .minimize(cost)


# Initializing the variables
# 初始化变量
init = tf.global_variables_initializer()

# Launch the graph
# 启动图
with tf.Session() as sess:
    sess.run(init)
    # Training cycle
    # 训练循环
    for epoch in range(training_epochs):
        total_batch = int(mnist.train.num_examples/batch_size)
        # Loop over all batches
        # 遍历所有 batch
        for i in range(total_batch):
            batch_x, batch_y = mnist.train.next_batch(batch_size)
            # Run optimization op (backprop) and cost op (to get loss value)
            # 运行优化器进行反向传导、计算 cost(获取 loss 值)
            sess.run(optimizer, feed_dict={x: batch_x, y: batch_y})

保存训练进度

在现实中,训练一个模型常常要用很长时间,若是由于某种原因 TensorFlow Session 被关闭,所有当前训练得到的权重(Weights)和偏差(Bias)都会丢失,需要重新训练。针对这种情况,TensorFlow 提供了一个 tf.train.Saver 的类用于把当前进程保存下来,这个过程本质上是把会话(Session)中所有 tf.Variable 存到你的文件系统。

### tensorflow_save_demo.py ###
import tensorflow as tf

# The file path to save the data
# 文件保存路径,保存为 .ckpt 文件
save_file = './model.ckpt'

# Two Tensor Variables: weights and bias
# 两个 Tensor 变量:权重和偏置项
weights = tf.Variable(tf.truncated_normal([2, 3]))
bias = tf.Variable(tf.truncated_normal([3]))

# Class used to save and/or restore Tensor Variables
# 用来存取 Tensor 变量的类
saver = tf.train.Saver()

with tf.Session() as sess:
    # Initialize all the Variables
    # 初始化所有变量
    sess.run(tf.global_variables_initializer())

    # Show the values of weights and bias
   # 显示变量和权重
    print('Weights:')
    print(sess.run(weights))
    print('Bias:')
    print(sess.run(bias))

    # Save the model
    # 保存模型
    saver.save(sess, save_file)

加载训练进度

把上面的代码所保存的进度(变量的值)加载到新模型里。
注意,你依然需要在 Python 中创建 weights 和 bias 两个 Tensor 。
使用 tf.train.Saver.restore() 函数把之前保存的数据加载到 weights 和 bias 当中。这里因为 tf.train.Saver.restore() 已经设定了 TensorFlow 变量,所以不需要再调用 tf.global_variables_initializer()了。


# Remove the previous weights and bias
# 移除之前的权重和偏置项
tf.reset_default_graph()

# Two Variables: weights and bias
# 两个变量:权重和偏置项
weights = tf.Variable(tf.truncated_normal([2, 3]))
bias = tf.Variable(tf.truncated_normal([3]))

# Class used to save and/or restore Tensor Variables
# 用来存取 Tensor 变量的类
saver = tf.train.Saver()

with tf.Session() as sess:
    # Load the weights and bias
    # 加载权重和偏置项
    saver.restore(sess, save_file)

    # Show the values of weights and bias
    # 显示权重和偏置项
    print('Weight:')
    print(sess.run(weights))
    print('Bias:')
    print(sess.run(bias))

打赏