声明:本文的主要内容及代码主要来源于实战Google深度学习框架
1.TensorFlow数据模型——张量
TensorFlow的张量和数学上的张量十分相似,简单来说可以用来表示一个多维数组,TensorFlow中实现张量并不是直接采用数组的形式,只是对运算结果的一个引用,如下:
import tensorflow as tf
a = tf.constant([1.0,2.0],name='a')
b = tf.constant([1.0,2.0],name='b')
result = tf.add(a,b,name='add')
print(result)
"""
输出:
Tensor("Add:0", shape=(2,), dtype=float32)
"""
以上看出输出的result并不是a和b的结果,只是一个张量的结构。张量保存了3个属性,名字、形状和类型。
名字 ”Add:0“ 表明它是通过加法得出。
形状 shape=(2,)表明它是一个长度为2的一维数组。
类型 dtype=float32 表明它是32为浮点数,张量中只有类型相同的才能够进行计算,否则会报告错误。
2. TensorFlow的运行模型——会话
上一节讲到定义好变量及其运算后,是不会自动进行计算的,要进行计算就需要调用TensorFlow里的会话来进行,以下两种会话的方式是我比较常用的。
#方法1
sess = tf.Session()
sess.run(result)
sess.close()
#方法2
with tf.Session() as sess:
sess.run(result)
以上两种方法都能够打印出result的结果。
两种方法不同之处在于第一种需要手动关闭sess会话,如果不关闭的话很可能会造成资源泄漏,而第二种方法,它的sess在with下运行,当运行结束后会自动释放资源。个人觉得第二种方法比较方便,避免忘记关闭会话而造成资源泄漏。
3.TensorFlow实现神经网络
以下通过一个用TensorFlow构建神经网络的例子来对TensorFlow的基本概念作一个大概的讲述。
假设现在需要判断零件的质量是否合格,目前已知的是每个零件的长度和重量。可以通过一个简单的神经网络来判断。
网络中
x
1
x_{1}
x1和
x
2
x_{2}
x2 是网络输入,因为已知是每个零件的长度和重量,所以输入是二维。
a
11
a
12
a
13
a_{11}a_{12}a_{13}
a11a12a13是隐藏层,由1x2的输入矩阵左乘2x3的
W
(
1
)
W^{(1)}
W(1)矩阵得出。
y是输出层,由1x3的隐藏层左乘3x1的
W
(
2
)
W^{(2)}
W(2)矩阵得出。
以上算法成为前向网络传播。
以下代码模拟该网络
#声明w1和w2矩阵
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 = tf.Constant([[0.7,0.9]])
#通过前向传播运算得出结果
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
sess = tf.Session()
sess.run(w1.initializer)
sess.run(w2.initializer)
print(sess.run(y))
sess.close()
以上算法可以输出3.957578。
因为w1和w2在网络中是需要变化的,所以需要将其声明为变量。而在sess.run当中,不能像开始一样直接sess.run(y)得出结果,要先对w1和w2进行初始化。
sess.run(w1.initializer())
是初始化的一种方法,但是如果网络中变量太多,可以用以下代码完成初始化。
init_op = tf.global_variables_initializer()
sess.run(init_op)
以上代码是针对输入只有1个例子的,如果输入有多个例子,针对每个粒子声明tf.Constant就不划算,这时可以将输入x声明为placeholder,其声明时不需要提供数据,只需要提供其所在位置以及名字,类型等即可,等进入session时再传输数据,如下:
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 = tf.placeholder(tf.float32,shape=(None,2),name="input")
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(y,feed_dict={x:[[0.7,0.9]]}))
以上代码同样能够输出正确结果,不同之处在于x现在被声明为placeholder,并且shape处声明为(None,2),说明参数为2列的数组,行数可以任意。然后在最后一行sess.run()运行时,在feed_dict中传入所需要的参数。feed_dict是一个字典,记录每个placeholder的参数。如果一次要运行多个例子,可以这样
print(sess.run(y,feed_dict={x:[[0.7,0.9],[0.1,0.4],[0.5,0.8]]}))
4.完整神经网络样例程序
以下先祭出代码:
import tensorflow as tf
from numpy.random import RandomState
#1.定义神经网络的参数,输入和输出节点
batch_size = 8
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 = tf.placeholder(tf.float32, shape=(None, 2), name="x-input")
y_= tf.placeholder(tf.float32, shape=(None, 1), name='y-input')
#2.定义前向传播过程,损失函数及反向传播算法。
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
y = tf.sigmoid(y)
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))
+ (1 - y_) * tf.log(tf.clip_by_value(1 - y, 1e-10, 1.0)))
train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
#3. 生成模拟数据集。
rdm = RandomState(1)
X = rdm.rand(128,2)
Y = [[int(x1+x2 < 1)] for (x1, x2) in X]
#4. 创建一个会话来运行TensorFlow程序
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
# 输出目前(未经训练)的参数取值。
print(sess.run(w1))
print(sess.run(w2))
print("\n")
# 训练模型。
STEPS = 5000
for i in range(STEPS):
start = (i*batch_size) % 128
end = (i*batch_size) % 128 + batch_size
sess.run([train_step, y, y_], 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))
# 输出训练后的参数取值。
print("\n")
print(sess.run(w1))
print(sess.run(w2))
代码第14行,定义了sigmoid激活函数,在矩阵计算完成后,通过引入非线性激活函数能够使网络具有更好的性能。
15行,定义了交叉熵损失函数,定义为
l
o
s
s
=
−
(
y
^
∗
(
l
o
g
y
)
+
(
1
−
y
^
)
∗
l
o
g
(
1
−
y
)
)
loss=-(\hat y*(logy)+(1-\hat y)*log(1-y))
loss=−(y^∗(logy)+(1−y^)∗log(1−y))
其中
y
^
\hat y
y^为标签真实值,y为模型预测值。
因为batch_size为8,每次训练时会取8个样本,计算损失函数时是计算这8个的均值。tf.clip_by_value是为了防止出现极小值,因为log0并无定义,如果y或1-y小于
1
0
−
10
10^{-10}
10−10,则其值为
1
0
−
10
10^{-10}
10−10。
17行,定义了优化器,用的是Adam方法,学习率是0.001,目标是最小化损失函数。
25行,会话开始。利用global_variables_initializer初始化w1和w2。设定了训练次数为5000次,每次训练都依次从数据集中选择8个样本,利用feed_dict传输给训练网络。
5总结
本文讲述了一些TensorFlow的基本概念,包括张量、会话的建立,以及如何初步建立一个简单的神经网络。