3.2 TensorFlow数据模型–张量
- 一个张量最重要的三个属性:名字(name)、维度(shape)、类型(dtype)
3.3 TensorFlow运行模型–会话
- ConfigProto最重要的参数有两个,第一个是allow_soft_placement。当它为True时,以下任意一个条件成立时,GPU的运算可以放到CPU上进行:
- 运算无法在GPU上运行。
- 没有GPU资源。
- 运算输入包括对CPU计算结果的引用。
另一个参数是log_device_placement,当它为True时日志将会记录每个节点被安排在哪个设备上方便调试。
import tensorflow.compat.v1 as tf
tf.disable_eager_execution()
a = tf.Variable(tf.constant([1.0]), name = 'a')
b = tf.Variable(tf.constant([2.0]), name = 'b')
result = a + b
config = tf.ConfigProto(allow_soft_placement=True,
log_device_placement=True) # 配置config
with tf.Session(config = config) as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(result))
3.4 TensorFlow实现神经网络
关于神经网络、前向后向传播的理论知识这里就不赘述了,主要注重TensorFlow的编程使用。
编程过程中常用函数
- Tensorflow随机数生成函数
函数名称 | 随机数分布 | 主要参数 |
---|---|---|
tf.random_normal | 正态分布 | 平均值、标准差、取值类型 |
tf.truncated_normal | 正态分布,但如果随机出来的值偏离平均值超过2个标准差,那么这个数将会被重新随机 | 平均值、标准差、取值类型 |
tf.random_uniform | 均匀分布 | 最小、最大取值、取值类型 |
tf.random_gamma | Gamma分布 | 形状参数alpha、尺度参数beta、取值类型 |
- Tensorflow常数生成函数
函数名称 | 功能 | 样例 |
---|---|---|
tf.Variable | 产生全0的数组 | tf.zeros([2,3], int32)->[[0,0,0],[0,0,0]] |
tf.ones | 产生全0的数组 | tf.ones([2,3], int32)->[[1,1,1],[1,1,1]] |
tf.fill | 产生一个全部为给定数字的数组 | tf.fill([2,3], 9)->[[9,9,9],[9,9,9]] |
tf.constant | 产生一个给定值的常量 | tf.constant([1,2,3])->[1,2,3] |
- Tensorflow变量生成函数
函数名称 | 功能 | 样例 |
---|---|---|
tf.Variable | 产生一个变量,可以用容器来初始化 | tf.Variable(tf.constant([1.0])) |
tf.placeholder | 占位函数 | tf.placeholder(shape=[None, 784], dtype=‘float’) |
- Tensorflow运算函数
函数名称 | 功能 | 样例 |
---|---|---|
tf.matmul | 对张量进行乘积,张量维度满足的要求和矩阵乘法相同 | tf.matmul(a,b) |
tf.sigmoid | sigmoid函数 | tf.sigmoid(x) |
… | … | … |
- Tensorflow优化器
常用优化器 |
---|
tf.train.GradientDescentOptimizer() |
tf.train.AdamOptimizer() |
tf.train.MomentumOptimizer() |
编程实现简单的神经网络
简单说下流程,这个代码不完全是照着书上写的,有我自己改的地方,加入了简单的batch。
-
定义数据集的大小为10000,随机生成10000个两特征的样本,根据两个特征的和对样本进行分类。
-
定义好网络结构,这个网络比较简单,只有输入层、隐藏层、输出层。隐藏层的神经元个数定为20个,隐藏层采用relu激活函数,可有效防止梯度消失。同时输出层采用sigmoid激活函数,输出值的范围在[0,1]之间,表示分类为1的概率。
-
利用输出值和真实的分类结果来计算cross entropy交叉熵。
l o s s = − ∑ 1 N ( p i l o g p i ′ + ( 1 − p i ) l o g ( 1 − p i ′ ) ) loss=-\sum_1^{N}(p_ilogp_i^{'}+(1-p_i)log(1-p_i^{'})) loss=−1∑N(pilogpi′+(1−pi)log(1−pi′))其中 p i p_i pi是真实结果, p i ′ p_i^{'} pi′是网络输出值,即分类概率。 -
利用Adam算法来优化损失函数。
-
一共进行20000次迭代,每次迭代训练batchSize个样本。程序设定的batchSize为2000,意味着每5次迭代取完整个训练集,然后继续重复。
代码
import tensorflow.compat.v1 as tf
import numpy as np
tf.disable_eager_execution()
dataNum = 10000 # 数据集大小为10000
batchSize = 2000 # 每次训练的batch为2000
trainData = np.random.randn(dataNum, 2) # 产生有两个特征的数据集, shape为(10000, 2)
trainLabel = np.array([int(x+y>0) for (x,y) in trainData]).reshape(-1, 1) # 若x+y>0归为1类, 否则归为0类
x = tf.placeholder(dtype='float', shape=[None, 2]) # 输入数据用占位函数,特征维度为2,None根据输入的batch自动判定
trueY = tf.placeholder(dtype='float', shape=[None, 1]) # 输出数据用占位函数
# 第一层全连接层
wFc1 = tf.Variable(tf.truncated_normal(shape=(2, 20), stddev=0.1)) # 初始化第一层的w,第一层神经元个数为20
bFc1 = tf.Variable(tf.constant(0.1, shape=[20])) # 初始化第一层的b
hFc1 = tf.nn.relu(tf.matmul(x, wFc1) + bFc1) # 激活函数选用relu函数
# 第二层全连接层
wFc2 = tf.Variable(tf.truncated_normal(shape=(20, 1), stddev=0.1)) # 初始化第二层的w,输出维度为1
bFc2 = tf.Variable(tf.constant(0.1, shape=[1])) # 初始化第二层的的b
predY = tf.nn.sigmoid(tf.matmul(hFc1, wFc2) + bFc2) # 输出选用sigmoid函数,把结果压缩到[0,1]区间,表示分类为1的概率值
# 定义损失函数,loss采用binary_cross_entropy(二值交叉熵)
# tf.clip_by_value(y, min, max)为剪枝函数,小于min取min,大于max取max,其余保持不变,防止log中出现0
loss = -tf.reduce_mean((trueY * tf.log(tf.clip_by_value(predY, 1e-10, 1))+ (1-trueY) * tf.log(tf.clip_by_value(1-predY, 1e-10, 1))))
trainStep = tf.train.AdamOptimizer(1e-3).minimize(loss) # 定义优化器优化目标
with tf.Session() as sess:
sess.run(tf.global_variables_initializer()) # 初始化所有变量
iters = 20000 # 迭代次数为20000次
for i in range(iters):
x_ = trainData[(i % 5) * batchSize:((i % 5) + 1) * batchSize, :] # 每次取batchSize个训练样本,每5次迭代重复整个训练集
y_ = trainLabel[(i % 5) * batchSize:((i % 5) + 1) * batchSize, :]
trainStep.run(feed_dict={
x: x_, trueY: y_}) # 拿batchSize个样本进行训练
if(i % 1000 == 0):
crossEntropy = loss.eval(feed_dict={
x: trainData, trueY: trainLabel}) # 每一千次迭代输出在整个训练集上的loss
print('iter:%d, loss: %g' % (i, crossEntropy))
运行结果
iter:0, loss: 0.669061
iter:1000, loss: 0.0590102
iter:2000, loss: 0.0314588
iter:3000, loss: 0.0210427
iter:4000, loss: 0.0154069
iter:5000, loss: 0.0118919
iter:6000, loss: 0.00953395
iter:7000, loss: 0.00789001
iter:8000, loss: 0.00671841
iter:9000, loss: 0.00586595
iter:10000, loss: 0.00523055
iter:11000, loss: 0.00474468
iter:12000, loss: 0.00436347
iter:13000, loss: 0.00405675
iter:14000, loss: 0.00380408
iter:15000, loss: 0.00359156
iter:16000, loss: 0.00340953
iter:17000, loss: 0.00325123
iter:18000, loss: 0.00311178
iter:19000, loss: 0.0029876
从结果可以看出,随着迭代次数的增加,神经网络在训练集上的训练误差越来越小,说明程序设定正确。
总结
训练神经网络的过程可以分成以下三个步骤:
- 定义神经网络结构和前向传播的输出结果。
- 定义损失函数和反向传播的优化算法。
- 生成会话并在训练数据上反复运行反向传播优化算法。
结语:以上内容和代码加入了自己的想法和验证,如有不当之处还请指正。
欢迎转载,标明出处。