1. TensorFlow是什么
TensorFlow官网说明如下:
TensorFlow™ is an open source software library for numerical computation using data flow graphs. Nodes in the graph represent mathematical operations, while the graph edges represent the multidimensional data arrays (tensors) communicated between them. The flexible architecture allows you to deploy computation to one or more CPUs or GPUs in a desktop, server, or mobile device with a single API. TensorFlow was originally developed by researchers and engineers working on the Google Brain Team within Google's Machine Intelligence research organization for the purposes of conducting machine learning and deep neural networks research, but the system is general enough to be applicable in a wide variety of other domains as well.
TensorFlow™是一个基于数据流图进行数值计算的开源软件库。图中的节点表示数学运算,而节点之间的边(链路)表示的是在这些节点之间进行某种联系的多维数组(tensor,张量)。这种灵活的结构允许我们使用简单的API将计算部署到桌面、服务器或者移动设备上的一个或者多个CPU或GPU。TensorFlow最开始是由Google Brain团队开发,旨在进行机器学习以及深度神经网络的研究,但现在这个系统大体上也已经足够适用于在一些其他的领域。
2. 基本使用
2.1 工作原理
TensorFlow的计算基于数据流图(data flow graphs)。图中的节点表示运算,称为op(operation的简称),一个op接收0个或者多个tensor并且执行某种操作或者计算,并且产生0个或者多个tensor。图中的边表示在节点之间流动的tensor(张量),在tensorflow中,我们可以将这种张量理解为多维数组,在TensorFlow中,所有的数据都是以tensor的形式存在的。
简单来说,tensorflow构建一个数据流图,将这些张量在链路中流动,在ops中进行运算最后输出结果,给一张图自己感受一下:

图片来源:Tinker With a Neural Network Right Here in Your Browser.
2.2 Variables(变量)
当我们在训练一个模型的时候,我们使用变量来保存和跟新参数,变量需要被初始化并且可以在训练完成后被保存在磁盘中以便后续利用。
变量的建立
当我们建立一个变量的时候,我们将一个tensor传递给Variable的构造函数,TensorFlow给我提供了一系列ops,这些ops提供一些用来初始化变量的tensor,详情可以查阅官方文档,下面我们先建立两个变量weights和biases:
# Create two variables.
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")
但需要注意的是:在建立变量的时候需要定义好变量的大小(shape),当然,TensorFlow也提供了一些方法用来修改,后面再说。
变量的位置
变量在创建的时候是可以被绑定在特定的设备上的,只要我们使用with tf.device(...)即可:
# Pin a variable to CPU.
with tf.device("/cpu:0"):
v = tf.Variable(...)
# Pin a variable to GPU.
with tf.device("/gpu:0"):
v = tf.Variable(...)
# Pin a variable to a particular parameter server task.
with tf.device("/job:ps/task:7"):
v = tf.Variable(...)
变量的初始化
TensorFlow中的变量必须初始化才能使用,最简单的初始化方法就是使用一个op执行为所有的变量进行初始化操作,并且在使用模型之前运行该op。当然,也可以使用checkpoint文件初始化变量(后面会说到)。
一般来说,我们可以使用tf.global_variables_initializer()来添加初始化操作,然后在会话中运行即可,如下代码所示:
# Create two variables.
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")
...
# Add an op to initialize the variables.
init_op = tf.global_variables_initializer()
# Later, when launching the model
with tf.Session() as sess:
# Run the init operation.
sess.run(init_op)
...
# Use the model
...
但是有时候,我们需要利用一个变量的初始化值来初始化某一个变量,但是tf.global_variables_initializer()操作是并行初始化所有变量的,在这种情况下,我们需要使用其他变量的initialized_value()属性,我们既可以直接用这个初始化后的值作为新变量的初始化值,也可以用任何tensor来计算新变量的初始化值,如下代码所示:
# Create a variable with a random value.
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
name="weights")
# Create another variable with the same value as 'weights'.
w2 = tf.Variable(weights.initialized_value(), name="w2")
# Create another variable with twice the value of 'weights'
w_twice = tf.Variable(weights.initialized_value() * 2.0, name="w_twice")
关于更多的初始化方面的内容,可以查阅官方文档
变量的存储与恢复
首先要说什么是checkpoint文件,简单来说,checkpoint文件就是用来存储变量的二进制文件,这个文件包含变量名到其对应tensor到值的映射。
我们首先创建一个Saver对象来管理模型中的所有变量:
# Create some variables.
v1 = tf.Variable(..., name="v1")
v2 = tf.Variable(..., name="v2")
...
# Add an op to initialize the variables.
init_op = tf.global_variables_initializer()
# Add ops to save and restore all the variables.
saver = tf.train.Saver()
# Later, launch the model, initialize the variables, do some work, save the
# variables to disk.
with tf.Session() as sess:
sess.run(init_op)
# Do some work with the model.
..
# Save the variables to disk.
save_path = saver.save(sess, "/tmp/model.ckpt")
print("Model saved in file: %s" % save_path)
在上面代码中,我们首先创建了两个变量v1和v2并初始化,然后我们使用tf.train.Saver()创建一个saver,然后在会话中的模型训练完成之后,将会话中所有变量存进磁盘中。
在变量存储的时候,我们可以为存进磁盘的变量设置名称,默认使用tf.Variable.name属性作为名称。
我们知道,我们训练模型的结果就是为了得到模型中的所有参数进行应用,所以当我们用了很长时间来训练了一个模型一个,我们就可以将其参数存储下来,到使用的时候直接使用训练完得到的checkpoint文件中存储的数据即可,举例来说:在TensorFlow中有一个使用CNN训练cifar10数据集的教程 ,其中就是把训练和评估放在不同的文件中,训练最终得到的数据存储下来用于评估。这种存储在长时间训练的时候尤其重要。所以下面来看看如何恢复变量:
# Create some variables.
v1 = tf.Variable(..., name="v1")
v2 = tf.Variable(..., name="v2")
...
# Add ops to save and restore all the variables.
saver = tf.train.Saver()
# Later, launch the model, use the saver to restore variables from disk, and
# do some work with the model.
with tf.Session() as sess:
# Restore variables from disk.
saver.restore(sess, "/tmp/model.ckpt")
print("Model restored.")
# Do some work with the model
...
在恢复变量的时候可以不初始化变量,直接在会话中运行restore()函数即可。
2.3 Tensor(张量)
在TensorFlow中,所有的数据都是以tensor的形式存在的,在图中的节点间数据只能以tensor的形式存在,可以简单理解为一个多维数组。
TensorFlow使用三个属性用来描述一个tensor的维度:rank, shape, dimension number
Rank
一个tensor的rank就是一个tensor维度的数量,比如,下面这个tensor的维度就是2:
t = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
通常来说,一个rank为2的tensor可以理解为一个矩阵,一个rank为1的tensor可以理解为一个集合。

一个简单看出rank值的方法就是直接看中括号,一个tensor最左侧左中括号数就是rank数。
Shape
TensorFlow官网提供的表格可以清晰描述rank、shape和dimension number的关系:

数据类型
下面是TensorFlow官网提供的表格:

2.4 Graph&Session
创建图
TensorFlow的计算是基于数据流图的,所以什么是图呢?我们看下面的代码:
import tensorflow as tf
mat1 = tf.constant([[3., 3.]])
mat2 = tf.constant([[2.],[2.]])
product = tf.matmul(mat1, mat2)
上面的代码创建了两个常量ops,然后创建一个matmul() op,这样这个默认的图就有了三个节点,然后我们开启一个会话来进行图的计算。
开启会话
import tensorflow as tf
mat1 = tf.constant([[3., 3.]])
mat2 = tf.constant([[2.],[2.]])
product = tf.matmul(mat1, mat2)
with tf.Session() as sess:
res = sess.run(product)
print(res)
...
我们先创建一个tf.Session()对象作为会话,然后在会话中使用run函数执行操作并且得到我们需要的结果。
当然也可以使用交互式会话InteractiveSession,可以查阅官方文档。
3. MNIST示例讲解
官方教程实践,这部分就以MNIST示例为主。
3.1 针对初学者的MNIST教程
首先说明,虽然本节所述的内容只针对TensorFlow的初学者,但是需要有ML和DL的基础知识,如果对MNIST问题不了解,可以先去阅读一下这本书:《Neural Networks and Deep Learning》
先给出一个最基础的神经网络训练MNIST数据的完整代码如下所示:
import tensorflow as tf
from MNIST import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W) + b)
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
for _ in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
上述代码汇总自TensorFlow官网,当然你也可以去GitHub找到更完整的版本。
我们将上面的代码分解开来看。首先,我们引入tensorflow包,input_data是一个加载数据集的py文件,你可以在这里下载放在当前路径下即可,这个文件可以自动下载该数据集。
import tensorflow as tf
from MNIST import input_data
接下来,我们用该文件提供的方法加载数据集。
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
我们需要两个占位符(placeholder)来表示输入,数据类型为tf.float32
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
这里的x和_y不是特定的值,而是占位符,x的维度为[None, 784]表示,可以代表任意个784维的向量(我们将28*28个像素点的图片转为一个784维的向量)即表示任意张图片,而 _y表示每一张图片的标签,因为是10个类,采用one-hot编码表示当前标签时,维度为[None, 10]。这两个占位符分别用来表示我们需要输入的用来训练的数据。
然后我们需要给出变量的定义,我们知道,在一个神经网络中必不可少的就是weight和bias,两者均以变量的形式存在。
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
接下来,我们根据上述的变量来构建模型:
y = tf.nn.softmax(tf.matmul(x, W) + b)
我们使用softmax回归来进行计算,这里的y就是我们神经网络的输出。
下面,我们使用交叉熵来表示结果与标签的差距,即损失:
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
使用梯度下降算法优化损失,设置学习速率为0.5。
经过上面的步骤,整个图就构建好了,我们开启会话:
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
然后每次从训练数据中取出100组数据进行训练,一共训练1000次:
for _ in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
这里可以看到,我们每一次从mnist中取出大小为100的一个batch,调用run函数计算上面的train_step,训练过程中,我们需要给上面的placeholder提供数据,即feed_dict。
最后,训练完成,我们计算一下准确度:
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
最后得到准确率大概在92%左右,一次训练就完成了,下面我们将采用CNN进行模型的训练,可以得到更高的准确率。
3.2 使用CNN训练MNIST
如何使用TensorFlow构建一个CNN来训练MNIST。
import MNIST.input_data as input_data
import tensorflow as tf
NUM_OF_CLASSES = 10
KEEP_DROP = 0.9
LEARNING_RATE = 0.01
NUM_OF_ITERATE = 200000
BATCH_SIZE = 50
# 获取训练和测试集
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# 卷积
def conv2d(name, x, weight, bias):
return tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x, weight, strides=[1, 1, 1, 1], padding='SAME'), bias=bias, name=name))
# 池化
def max_pool(name, x, strides=2, ksize=2):
return tf.nn.max_pool(x, ksize=[1, ksize, ksize, 1], strides=[1, strides, strides, 1], padding='SAME')
# 正则化
def norm(name, input, lsize=4):
return tf.nn.lrn(input, lsize, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name=name)
# 占位符
# 数据量较小
x = tf.placeholder('float', [None, 784])
y_ = tf.placeholder('float', [None,10])
# weights和biases
weights = {
'wc1': tf.Variable(tf.random_normal([5, 5, 1, 32])),
'wc2': tf.Variable(tf.random_normal([5, 5, 32, 64])),
'wf1': tf.Variable(tf.random_normal([7*7*64, 1024])),
'wf2': tf.Variable(tf.random_normal([1024, 1024])),
'out': tf.Variable(tf.random_normal([1024, 10])),
}
biases = {
'bc1': tf.Variable(tf.random_normal([32])),
'bc2': tf.Variable(tf.random_normal([64])),
'bf1': tf.Variable(tf.random_normal([1024])),
'bf2': tf.Variable(tf.random_normal([1024])),
'out': tf.Variable(tf.random_normal([10]))
}
def inference(_image, _weights, _biases, _dropout=1.0):
"""
the whole model
:param _image: input image, 2D Tensor
:param _weights: the dict of weight
:param _biases: the dict of bias
:param _dropout: the probability of reserved in every layer
:return: softmax
"""
# reshape
_image = tf.reshape(_image, [-1, 28, 28, 1])
tf.summary.image('image', _image)
# conv1
with tf.name_scope('conv1') as scope:
conv1 = conv2d(name='conv1', x=_image, weight=_weights['wc1'], bias=_biases['bc1'])
pool1 = max_pool('pool1', conv1)
norm1 = norm('norm1', pool1, lsize=4)
norm1 = tf.nn.dropout(norm1, _dropout)
# conv2
with tf.name_scope('conv2') as scope:
conv2 = conv2d(name='conv2', x=norm1, weight=_weights['wc2'], bias=_biases['bc2'])
pool2 = max_pool('pool2', conv2)
norm2 = norm('norm2', pool2, lsize=4)
norm2 = tf.nn.dropout(norm2, _dropout)
fc = tf.reshape(norm2, [-1, _weights['wf1'].get_shape().as_list()[0]])
with tf.name_scope('full_con1') as scope:
fc1 = tf.nn.relu(tf.matmul(fc, _weights['wf1']) + _biases['bf1'], name='fc1')
# with tf.name_scope('full_con2') as scope:
# fc2 = tf.nn.relu(tf.matmul(fc1, _weights['wf2']) + _biases['bf2'], name='fc2')
with tf.name_scope('softmax') as scope:
softmax = tf.nn.bias_add(tf.matmul(fc1, _weights['out']), _biases['out'], name='softmax')
return softmax
logits = inference(x, weights, biases, KEEP_DROP)
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
logits=logits, labels=y_, name='cross_entropy'))
tf.summary.scalar('loss', cross_entropy)
train_step = tf.train.AdamOptimizer(LEARNING_RATE).minimize(cross_entropy)
correct_pred = tf.equal(tf.argmax(logits,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
tf.summary.scalar('accuracy', accuracy)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
summary = tf.summary.merge_all()
summary_writer = tf.summary.FileWriter("MNIST_summary/", sess.graph)
step = 1
while BATCH_SIZE * step <= NUM_OF_ITERATE:
images, labels = mnist.train.next_batch(BATCH_SIZE)
feed_dict={x: images, y_: labels}
_, summary_str, acc, loss = sess.run([train_step, summary, accuracy, cross_entropy], feed_dict=feed_dict)
if step%100 == 0:
summary_writer.add_summary(summary_str, step)
print("Iter " + str(step * BATCH_SIZE) + ", Minibatch Loss= " + "{:.6f}".format(
loss) + ", Training Accuracy= " + "{:.5f}".format(acc))
step += 1
print('complete!')
模型是仿照的AlexNet,使用的是两个卷积层和两个全连层(后来注释掉一个全连层),用到了summary,具体可视化相关的内容可以在官网看一下。
3.3 使用RNN训练MNIST
论文提出一种针对姿态捕捉的叫Part-Aware LSTM的模型,骨骼数据集
这里给一个用RNN训练MNIST的代码,效果还不错,大概能达到97%-98%左右。
import tensorflow as tf
from MNIST import input_data
# set random seed
tf.set_random_seed(1)
# 导入数据
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
learningrate = 0.001
training_iters = 100000
batch_size = 128
n_inputs = 28
n_steps = 28
n_hidden_units = 128
n_classes = 10
x = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
y = tf.placeholder(tf.float32, [None, n_classes])
weights = {
'in': tf.Variable(tf.random_normal([n_inputs, n_hidden_units])),
'out': tf.Variable(tf.random_normal([n_hidden_units, n_classes]))
}
biases = {
'in': tf.Variable(tf.constant(0.1, shape=[n_hidden_units])),
'out': tf.Variable(tf.constant(0.1, shape=[n_classes]))
}
def RNN(X, weights, biases):
X = tf.reshape(X, [-1, n_inputs])
X_in = tf.matmul(X, weights['in']) + biases['in']
X_in = tf.reshape(X_in, [-1, n_steps, n_hidden_units])
# basic LSTM Cell.
lstm_cell = tf.contrib.rnn.BasicLSTMCell(n_hidden_units, forget_bias=1.0, state_is_tuple=True)
init_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)
outputs, final_state = tf.nn.dynamic_rnn(lstm_cell, X_in, initial_state=init_state, time_major=False)
outputs = tf.unstack(tf.transpose(outputs, [1, 0, 2]))
results = tf.matmul(outputs[-1], weights['out']) + biases['out']
return results
pred = RNN(x, weights, biases)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
train_op = tf.train.AdamOptimizer(learningrate).minimize(cost)
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
step = 0
while step * batch_size < training_iters:
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
batch_xs = batch_xs.reshape([batch_size, n_steps, n_inputs])
sess.run([train_op], feed_dict={x: batch_xs, y: batch_ys})
if step % 20 == 0:
print(sess.run(accuracy, feed_dict={x: batch_xs, y: batch_ys}))
step += 1
评论列表(0条)