TensorFlow学习笔记(二)

一、神经网络优化

神经元模型:用数学公式表示为:
在这里插入图片描述
神经网络是以神经元为基本单元构成的。

激活函数:引入非线性激活因素,提高模型的表达力。

常用的激活函数有relu、sigmoid、tanh等。

① 激活函数relu: 在Tensorflow中,用tf.nn.relu()表示
在这里插入图片描述
在这里插入图片描述
② 激活函数sigmoid:在Tensorflow中,用tf.nn.sigmoid()表示
在这里插入图片描述
在这里插入图片描述
③ 激活函数tanh:在Tensorflow中,用tf.nn.tanh()表示
在这里插入图片描述
在这里插入图片描述
神经网络的复杂度:可用神经网络的层数和神经网络中待优化参数个数表示

神经网路的层数:一般不计入输入层,层数 = n个隐藏层 + 1个输出层

神经网路待优化的参数:神经网络中所有参数w的个数 + 所有参数b的个数

例如:
在这里插入图片描述
在该神经网络中,包含1个输入层、1个隐藏层和1个输出层,该神经网络的层数为2层。 在该神经网络中,参数的个数是所有参数w的个数加上所有参数b的总数,第一层参数用三行四列的二阶张量表示(即12个线上的权重w)再加上4个偏置b;第二层参数是四行两列的二阶张量(即8个线上的权重w)再加上2个偏置b。总参数 = 34+4 + 42+2 = 26。

损失函数(loss):用来表示预测值(y)与已知答案(y_)的差距。在训练神经网络时,通过不断改变神经网络中所有参数,使损失函数不断减小,从而训练出更高准确率的神经网络模型。

常用的损失函数有均方误差、自定义和交叉熵等。

均方误差mse:n个样本的预测值y与已知答案y_之差的平方和,再求平均值。
在这里插入图片描述
在Tensorflow中用loss_mse = tf.reduce_mean(tf.square(y_ - y))

例如:预测酸奶日销量 y,x1和 x2 是影响日销量的两个因素。应提前采集的数据有:一段时间内,每日的 x1 因素、x2因素和销量 y_。采集的数据尽量多。在本例中用销量预测产量,最优的产量应该等于销量。由于目前没有数据集,所以拟造了一套数据集。利用 Tensorflow 中函数随机生成 x1、 x2,制造标准答案y_= x1 + x2,为了更真实,求和后还加了正负 0.05 的随机噪声。 我们把这套自制的数据集喂入神经网络,构建一个一层的神经网络,拟合预测酸奶日销量的函数。

示例代码:

# 预测多或预测少的影响一样
# 0.导入模块,生成数据集
import tensorflow as tf
import numpy as np
BATCH_SIZE = 8
SEED = 23455
 
rdm = np.random.RandomState(SEED)
X = rdm.rand(32,2)
Y_ = [[x1+x2+(rdm.rand()/10.0-0.05)] for (x1, x2) in X]
 
# 1.定义神经网络的输入、参数和输出,定义前向传播过程。
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
w1= tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w1)
 
# 2.定义损失函数及反向传播方法。
# 定义损失函数为MSE,反向传播方法为梯度下降。
loss_mse = tf.reduce_mean(tf.square(y_ - y))
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss_mse)
# train_step = tf.train.MomentumOptimizer(0.001,0.9).minimize(loss_mse)  
# train_step = tf.train.AdamOptimizer(0.001).minimize(loss_mse)
 
# 3.生成会话,训练STEPS轮
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    STEPS = 20000
    for i in range(STEPS):
        start = (i*BATCH_SIZE) % 32
        end = (i*BATCH_SIZE) % 32 + BATCH_SIZE
        sess.run(train_step, feed_dict={x: X[start:end], y_: Y_[start:end]})
        if i % 500 == 0:
            print("After %d training steps, w1 is: " % (i))
            print(sess.run(w1), "\n")
    print("Final w1 is: \n", sess.run(w1))
# 在本代码#2中尝试其他反向传播方法,看对收敛速度的影响

运行结果如下:
在这里插入图片描述
由上述代码可知,本例中神经网络预测模型为y = w1x1 +w2x2,损失函数采用均方误差。通过使损失函数值(loss)不断降低,神经网络模型得到最终参数w1=0.98,w2=1.02,销量预测结果为y =0.98x1 +1.02x2。由于在生成数据集时,标准答案为y = x1+ x2,因此,销量预测结果和标准答案已非常接近,说明该神经网络预测酸奶日销量正确。

自定义损失函数:根据问题的实际情况,定制合理的损失函数。

例如:

对于预测酸奶日销量问题,如果预测销量大于实际销量则会损失成本;如果预测销量小于实际销量则会损失利润。在实际生活中,往往制造一盒酸奶的成本和销售一盒酸奶的利润是不等价的。因此,需要使用符合该问题的自定义损失函数。

自定义损失函数为:
在这里插入图片描述
其中,损失定义成分段函数:
在这里插入图片描述
损失函数表示,若预测结果 y 小于标准答案 y_,损失函数为利润乘以预测结果y 与标准答案 y_之差;若预测结果 y大于标准答案 y_,损失函数为成本乘以预测结果 y 与标准答案 y_之差。

用 Tensorflow 函数表示为:
loss =tf.reduce_sum(tf.where(tf.greater(y,y_),COST(y-y_),PROFIT(y_-y)))
① 若酸奶成本为1元,酸奶销售利润为9元,则制造成本小于酸奶利润,因此希望预测的结果y多一些。采用上述的自定义损失函数,训练神经网络模型。

示例代码:

# 酸奶成本1元, 酸奶利润9元
# 预测少了损失大,故不要预测少,故生成的模型会多预测一些
# 0.导入模块,生成数据集
import tensorflow as tf
import numpy as np
BATCH_SIZE = 8
SEED = 23455
COST = 1
PROFIT = 9
 
rdm = np.random.RandomState(SEED)
X = rdm.rand(32,2)
Y = [[x1+x2+(rdm.rand()/10.0-0.05)] for (x1, x2) in X]
 
# 1.定义神经网络的输入、参数和输出,定义前向传播过程。
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
w1= tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w1)
 
# 2.定义损失函数及反向传播方法。
# 定义损失函数使得预测少了的损失大,于是模型应该偏向多的方向预测。
loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_)*COST, (y_ - y)*PROFIT))
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss)
 
# 3.生成会话,训练STEPS轮。
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    STEPS = 3000
    for i in range(STEPS):
        start = (i*BATCH_SIZE) % 32
        end = (i*BATCH_SIZE) % 32 + BATCH_SIZE
        sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 500 == 0:
            print("After %d training steps, w1 is: " % (i))
            print(sess.run(w1), "\n")
    print("Final w1 is: \n", sess.run(w1))

运行结果如下:
在这里插入图片描述
由代码执行结果可知,神经网络最终参数为 w1=1.03, w2=1.05,销量预测结果为 y =1.03x1 + 1.05x2。由此可见,采用自定义损失函数预测的结果大于采用均方误差预测的结果,更符合实际需求。

②若酸奶成本为 9元,酸奶销售利润为 1 元,则制造成本大于酸奶利润,因此希望预测结果 y 小一些。采用上述的自定义损失函数,训练神经网络模型。

示例代码:

# 酸奶成本9元, 酸奶利润1元
# 预测多了损失大,故不要预测多,故生成的模型会少预测一些
# 0.导入模块,生成数据集
import tensorflow as tf
import numpy as np
BATCH_SIZE = 8
SEED = 23455
COST = 9
PROFIT = 1
 
rdm = np.random.RandomState(SEED)
X = rdm.rand(32,2)
Y = [[x1+x2+(rdm.rand()/10.0-0.05)] for (x1, x2) in X]
 
# 1.定义神经网络的输入、参数和输出,定义前向传播过程。
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
w1= tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w1)
 
# 2.定义损失函数及反向传播方法。
# 重新定义损失函数,使得预测多了的损失大,于是模型应该偏向少的方向预测。
loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_)*COST, (y_ - y)*PROFIT))
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss)
 
# 3.生成会话,训练STEPS轮。
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    STEPS = 3000
    for i in range(STEPS):
        start = (i*BATCH_SIZE) % 32
        end = (i*BATCH_SIZE) % 32 + BATCH_SIZE
        sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 500 == 0:
            print("After %d training steps, w1 is: " % (i))
            print(sess.run(w1), "\n")
    print("Final w1 is: \n", sess.run(w1))

运行结果如下:
在这里插入图片描述
由执行结果可知,神经网络最终参数为w1=0.96,w2=0.97,销量预测结果为y =0.96x1 + 0.97x2。因此,采用自定义损失函数预测的结果小于采用均方误差预测的结果,更符合实际需求。

交叉熵(Cross Entropy):表示两个概率分布之间的距离。交叉熵越大,两个概率分布距离越远,两个概率分布越相异;交叉熵越小,两个概率分布距离越近,两个概率分布越相似。

交叉熵计算公式:

用Tensorflow函数表示为ce= -tf.reduce_mean(y_* tf.log(tf.clip_by_value(y,1e-12, 1.0)))

例如: 两个神经网络模型解决二分类问题中,已知标准答案为 y_ = (1, 0),第一个神经网络模型预测结果为 y1=(0.6,0.4),第二个神经网络模型预测结果为 y2=(0.8, 0.2),判断哪个神经网络模型预测的结果更接近标准答案。根据交叉熵的计算公式得:

H1((1,0),(0.6,0.4)) = -(1log0.6 + 0log0.4) ≈ -(-0.222 + 0) = 0.222
H2((1,0),(0.8,0.2)) = -(1log0.8 + 0log0.2) ≈ -(-0.097 + 0) = 0.097
由于 0.222>0.097,所以预测结果 y2 与标准答案 y_更接近,y2预测更准确。

softmax 函数:将 n 分类的 n 个输出(y1,y2…yn)变为满足以下概率分布要求的函数。
在这里插入图片描述
softmax函数表示为:
在这里插入图片描述
softmax 函数应用:在 n 分类中,模型会有 n 个输出,即 y1,y2…yn,其中yi 表示第 i 种情况出现的可能性大小。将 n 个输出经过 softmax 函数,可得到符合概率分布的分类结果。

在 Tensorflow 中,一般让模型的输出经过 sofemax 函数,以获得输出分类的概率分布,再与标准答案对比,求出交叉熵,得到损失函数,用如下函数实现:

ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_,1)) 
cem = tf.reduce_mean(ce) 

学习率

学习率 learning_rate:表示了每次参数更新的幅度大小。学习率过大,会导致待优化的参数在最

小值附近波动,不收敛;学习率过小,会导致待优化的参数收敛缓慢。 在训练过程中,参数的更新向着损失函数梯度下降的方向。 参数的更新公式为:
在这里插入图片描述
假设损失函数为loss = (w + 1)2。梯度是损失函数loss的导数为 ∇=2w+2。如参数初值为5,学习率为0.2,则参数和损失函数更新如下:

1次 参数w:5 5 - 0.2 * (2 * 5 +2) = 2.6

2次 参数w:2.6 2.6 - 0.2 * (2 *2.6 + 2) = 1.16

3次 参数w:1.16 1.16 – 0.2 * (2 *1.16 + 2) = 0.296

4次 参数w:0.296 损失函数loss = (w + 1)2的图像为:
在这里插入图片描述
由图可知,损失函数loss的最小值会在(-1,0)处得到,此时损失函数的导数为0,得到最终参数w =-1。

示例代码:

# 设损失函数 loss=(w+1)^2, 令w初值是常数5。反向传播就是求最优w,即求最小loss对应的w值
import tensorflow as tf
# 定义待优化参数w初值赋5
w = tf.Variable(tf.constant(5, dtype=tf.float32))
# 定义损失函数loss
loss = tf.square(w+1)
# 定义反向传播方法
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
# 生成会话,训练40轮
with tf.Session() as sess:
    init_op=tf.global_variables_initializer()
    sess.run(init_op)
    for i in range(40):
        sess.run(train_step)
        w_val = sess.run(w)
        loss_val = sess.run(loss)
        print("After %s steps: w is %f,   loss is %f." % (i, w_val,loss_val))

运行结果如下:
在这里插入图片描述
由结果可知,随着损失函数值的减小,w无限趋近于-1,模型计算推测出最优参数w = -1。

学习率的设置 学习率过大,会导致待优化的参数在最小值附近波动,不收敛;学习率过小,会导致待优化的参数收敛缓慢。

例如:

① 对于上例的损失函数loss= (w + 1)2。则将上述代码中学习率修改为 1,其余内容不变。
在这里插入图片描述

实验结果如下:
在这里插入图片描述
由运行结果可知,损失函数 loss 值并没有收敛,而是在 5 和-7 之间波动。

②对于上例的损失函数loss = (w + 1)2。则将上述代码中学习率修改为0.0001,其余内容不变。
在这里插入图片描述
实验结果如下:
在这里插入图片描述
由运行结果可知,损失函数 loss 值缓慢下降,w值也在小幅度变化,收敛缓慢。

指数衰减学习率:学习率随着训练轮数变化而动态更新 学习率计算公式如下:
在这里插入图片描述
用 Tensorflow 的函数表示为:

global_step = tf.Variable(0,trainable=False) 
learning_rate = tf.train.exponential_decay(
LEARNING_RATE_BASE, 
global_step, 
LEARNING_RATE_STEP,LEARNING_RATE_DECAY, staircase=True/False)

其中,LEARNING_RATE_BASE为学习率初始值,LEARNING_RATE_DECAY为学习率衰减率,global_step记录了当前训练轮数,为不可训练型参数。学习率 learning_rate更新频率为输入数据集总样本数除以每次喂入样本数。若staircase设置为True时,表示global_step/learning rate step取整数,学习率阶梯型衰减;若staircase设置为false时,学习率会是一条平滑下降的曲线。 例如: 在本例中,模型训练过程不设定固定的学习率,使用指数衰减学习率进行训练。其中,学习率初值设置为0.1,学习率衰减率设置为0.99,BATCH_SIZE设置为1。

示例代码:

# 设损失函数 loss=(w+1)^2, 令w初值是常数10。反向传播就是求最优w,即求最小loss对应的w值
# 使用指数衰减的学习率,在迭代初期得到较高的下降速度,可以在较小的训练轮数下取得更有收敛度。
import tensorflow as tf
 
LEARNING_RATE_BASE = 0.1 #最初学习率
LEARNING_RATE_DECAY = 0.99 #学习率衰减率
LEARNING_RATE_STEP = 1  #喂入多少轮BATCH_SIZE后,更新一次学习率,一般设为:总样本数/BATCH_SIZE
 
# 运行了几轮BATCH_SIZE的计数器,初值给0, 设为不被训练
global_step = tf.Variable(0, trainable=False)
# 定义指数下降学习率
learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE, global_step, LEARNING_RATE_STEP, LEARNING_RATE_DECAY, staircase=True)
# 定义待优化参数,初值给10
w = tf.Variable(tf.constant(5, dtype=tf.float32))
# 定义损失函数loss
loss = tf.square(w+1)
# 定义反向传播方法
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
# 生成会话,训练40轮
with tf.Session() as sess:
    init_op=tf.global_variables_initializer()
    sess.run(init_op)
    for i in range(40):
        sess.run(train_step)
        learning_rate_val = sess.run(learning_rate)
        global_step_val = sess.run(global_step)
        w_val = sess.run(w)
        loss_val = sess.run(loss)
        print("After %s steps: global_step is %f, w is %f, learning rate is %f, loss is %f" % (i, global_step_val, w_val, learning_rate_val, loss_val))

运行结果如下:
在这里插入图片描述
由结果可以看出,随着训练轮数增加学习率在不断减小。
滑动平均

滑动平均:记录了一段时间内模型中所有参数w和b各自的平均值。利用滑动平均值可以增强模型的泛化能力。

滑动平均值(影子)计算公式:

影子 = 衰减率 * 影子 +(1 - 衰减率)* 参数

其中,衰减率,影子初值=参数初值

用Tesnsorflow函数表示为:

ema =tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)

其中,MOVING_AVERAGE_DECAY表示滑动平均衰减率,一般会赋接近1的值,global_step表示当前训练了多少轮。

ema_op =ema.apply(tf.trainable_variables())

其中,ema.apply()函数实现对括号内参数求滑动平均,tf.trainable_variables()函数实现把所有待训练参数汇总为列表。

with tf.control_dependencies([train_step,ema_op]):
     train_op = tf.no_op(name='train')

其中,该函数实现将滑动平均和训练过程同步运行。

查看模型中参数的平均值,可以用ema.average()函数。 例如:

在神经网络模型中,将MOVING_AVERAGE_DECAY设置为0.99,参数w1设置为0,w1的滑动平均值设置为0。

①开始时,轮数global_step设置为0,参数w1更新为1,则w1的滑动平均值为:

w1滑动平均值=min(0.99,1/10)*0+(1–min(0.99,1/10)*1 = 0.9

②当轮数global_step设置为100时,参数w1更新为10,则滑动平均值变为:

w1滑动平均值=min(0.99,101/110)*0.9+(1–min(0.99,101/110)*10 = 0.826+0.818=1.644

③再次运行,参数w1更新为1.644,则滑动平均值变为:

w1滑动平均值=min(0.99,101/110)*1.644+(1–min(0.99,101/110)*10 = 2.328

④再次运行,参数w1更新为2.328,则滑动平均值:

w1滑动平均值=2.956

示例代码:

import tensorflow as tf
 
# 1. 定义变量及滑动平均类
# 定义一个32位浮点变量,初始值为0.0  这个代码就是不断更新w1参数,优化w1参数,滑动平均做了个w1的影子
w1 = tf.Variable(0, dtype=tf.float32)
# 定义num_updates(NN的迭代轮数),初始值为0,不可被优化(训练),这个参数不训练
global_step = tf.Variable(0, trainable=False)
# 实例化滑动平均类,给衰减率为0.99,当前轮数global_step
MOVING_AVERAGE_DECAY = 0.99
ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
# ema.apply后的括号里是更新列表,每次运行sess.run(ema_op)时,对更新列表中的元素求滑动平均值。
# 在实际应用中会使用tf.trainable_variables()自动将所有待训练的参数汇总为列表
# ema_op = ema.apply([w1])
ema_op = ema.apply(tf.trainable_variables())
 
# 2. 查看不同迭代中变量取值的变化。
with tf.Session() as sess:
    # 初始化
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
	# 用ema.average(w1)获取w1滑动平均值 (要运行多个节点,作为列表中的元素列出,写在sess.run中)
	# 打印出当前参数w1和w1滑动平均值
    print("current global_step:", sess.run(global_step))
    print("current w1", sess.run([w1, ema.average(w1)])) 
    
    # 参数w1的值赋为1
    sess.run(tf.assign(w1, 1))
    sess.run(ema_op)
    print("current global_step:", sess.run(global_step))
    print("current w1", sess.run([w1, ema.average(w1)])) 
    
    # 更新global_step和w1的值,模拟出轮数为100时,参数w1变为10, 以下代码global_step保持为100,每次执行滑动平均操作,影子值会更新 
    sess.run(tf.assign(global_step, 100))  
    sess.run(tf.assign(w1, 10))
    sess.run(ema_op)
    print("current global_step:", sess.run(global_step))
    print("current w1:", sess.run([w1, ema.average(w1)]))       
    
    # 每次sess.run会更新一次w1的滑动平均值
    sess.run(ema_op)
    print("current global_step:" , sess.run(global_step))
    print("current w1:", sess.run([w1, ema.average(w1)]))
 
    sess.run(ema_op)
    print("current global_step:" , sess.run(global_step))
    print("current w1:", sess.run([w1, ema.average(w1)]))
 
    sess.run(ema_op)
    print("current global_step:" , sess.run(global_step))
    print("current w1:", sess.run([w1, ema.average(w1)]))
 
    sess.run(ema_op)
    print("current global_step:" , sess.run(global_step))
    print("current w1:", sess.run([w1, ema.average(w1)]))
 
    sess.run(ema_op)
    print("current global_step:" , sess.run(global_step))
    print("current w1:", sess.run([w1, ema.average(w1)]))
 
    sess.run(ema_op)
    print("current global_step:" , sess.run(global_step))
    print("current w1:", sess.run([w1, ema.average(w1)]))
 
# 更改MOVING_AVERAGE_DECAY 为 0.1  看影子追随速度

运行结果如下:
在这里插入图片描述
从运行结果可知,最初参数w1和滑动平均值都是0;参数w1设定为1后,滑动平均值变为0.9;当迭代轮数更新为100轮时,参数w1更新为10后,滑动平均值变为1.644。随后每执行一次,参数 w1的滑动平均值都向参数w1靠近。可见,滑动平均追随参数的变化而变化。
正则化

过拟合:神经网络模型在训练数据集上的准确率较高,在新的数据进行预测或分类时准确率较低,说明模型的泛化能力差。

正则化:在损失函数中给每个参数w加上权重,引入模型复杂度指标,从而抑制模型噪声,减小过拟合。

使用正则化后,损失函数loss变为两项之和:

loss = loss(y与y_)+ REGULARIZER*loss(w)

其中,第一项是预测结果与标准答案之间的差距,如之前讲过的交叉熵、均方误差等;第二项是正则化计算结果。

正则化计算方法:
① L1正则化:
在这里插入图片描述
用Tesnsorflow函数表示:loss(w)= tf.contrib.layers.l1_regularizer(REGULARIZER)(w)
② L2正则化:
在这里插入图片描述
用Tesnsorflow函数表示:loss(w)= tf.contrib.layers.l2_regularizer(REGULARIZER)(w)

用Tesnsorflow函数实现正则化:

tf.add_to_collection(‘losses’,tf.contrib.layers.l2_regularizer(regularizer)(w) loss = cem +tf.add_n(tf.get_collection(‘losses’))

cem的计算已在4.1节中给出。

例如:

用300个符合正态分布的点X[x0, x1]作为数据集,根据点X[x0, x1]计算生成标注Y_,将数据集标注为红色点和蓝色点。

标注规则为:当x02 + x12 < 2 时,y_=1,标注为红色;当x02 + x122 时,y_=0,标注为蓝色。

我们分别用无正则化和有正则化两种方法,拟合曲线,把红色点和蓝色点分开。在实际分类时,如果前向传播输出的预测值y接近1则为红色点概率越大,接近0则为蓝色点概率越大,输出的预测值y为0.5是红蓝点概率分界线。

在本例子中,我们使用了之前未用过的模块与函数:

matplotlib模块:Python中的可视化工具模块,实现函数可视化

终端安装指令:

sudo apt install python-tk
pip install matplotlib

函数plt.scatter():利用指定颜色实现点(x,y)的可视化

plt.scatter (x坐标, y坐标, c=”颜色”)

plt.show()

收集规定区域内所有的网格坐标点:

xx, yy = np.mgrid[起:止:步长, 起:止:步长] #找到规定区域以步长为分辨率的行列网格坐标点

grid = np.c_[xx.ravel(), yy.ravel()] #收集规定区域内所有的网格坐标点

plt.contour()函数:告知x、y坐标和各点高度,用levels指定高度的点描上颜色

plt.contour (x轴坐标值, y轴坐标值, 该点的高度,levels=[等高线的高度]) plt.show()

示例代码如下:

# 0.导入模块 ,生成模拟数据集
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
BATCH_SIZE = 30 
seed = 2 
# 基于seed产生随机数
rdm = np.random.RandomState(seed)
# 随机数返回300行2列的矩阵,表示300组坐标点(x0,x1)作为输入数据集
X = rdm.randn(300,2)
# 从X这个300行2列的矩阵中取出一行,判断如果两个坐标的平方和小于2,给Y赋值1,其余赋值0
# 作为输入数据集的标签(正确答案)
Y_ = [int(x0*x0 + x1*x1 <2) for (x0,x1) in X]
# 遍历Y中的每个元素,1赋值'red'其余赋值'blue',这样可视化显示时人可以直观区分
Y_c = [['red' if y else 'blue'] for y in Y_]
# 对数据集X和标签Y进行shape整理,第一个元素为-1表示,随第二个参数计算得到,第二个元素表示多少列,把X整理为n行2列,把Y整理为n行1列
X = np.vstack(X).reshape(-1,2)
Y_ = np.vstack(Y_).reshape(-1,1)
print(X)
print(Y_)
print(Y_c)
# 用plt.scatter画出数据集X各行中第0列元素和第1列元素的点即各行的(x0,x1),用各行Y_c对应的值表示颜色(c是color的缩写) 
plt.scatter(X[:,0], X[:,1], c=np.squeeze(Y_c)) 
plt.show()
 
 
# 定义神经网络的输入、参数和输出,定义前向传播过程 
def get_weight(shape, regularizer):
	w = tf.Variable(tf.random_normal(shape), dtype=tf.float32)
	tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))
	return w
 
def get_bias(shape):  
    b = tf.Variable(tf.constant(0.01, shape=shape)) 
    return b
	
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
 
w1 = get_weight([2,11], 0.01)	
b1 = get_bias([11])
y1 = tf.nn.relu(tf.matmul(x, w1)+b1)
 
w2 = get_weight([11,1], 0.01)
b2 = get_bias([1])
y = tf.matmul(y1, w2)+b2 
 
# 定义损失函数
loss_mse = tf.reduce_mean(tf.square(y-y_))
loss_total = loss_mse + tf.add_n(tf.get_collection('losses'))
 
#定义反向传播方法:不含正则化
train_step = tf.train.AdamOptimizer(0.0001).minimize(loss_mse)
 
with tf.Session() as sess:
	init_op = tf.global_variables_initializer()
	sess.run(init_op)
	STEPS = 40000
	for i in range(STEPS):
		start = (i*BATCH_SIZE) % 300
		end = start + BATCH_SIZE
		sess.run(train_step, feed_dict={x:X[start:end], y_:Y_[start:end]})
		if i % 2000 == 0:
			loss_mse_v = sess.run(loss_mse, feed_dict={x:X, y_:Y_})
			print("After %d steps, loss is: %f" %(i, loss_mse_v))
    # xx在-3到3之间以步长为0.01,yy在-3到3之间以步长0.01,生成二维网格坐标点
	xx, yy = np.mgrid[-3:3:.01, -3:3:.01]
	# 将xx , yy拉直,并合并成一个2列的矩阵,得到一个网格坐标点的集合
	grid = np.c_[xx.ravel(), yy.ravel()]
	# 将网格坐标点喂入神经网络 ,probs为输出
	probs = sess.run(y, feed_dict={x:grid})
	# probs的shape调整成xx的样子
	probs = probs.reshape(xx.shape)
	print("w1:\n",sess.run(w1))
	print("b1:\n",sess.run(b1))
	print("w2:\n",sess.run(w2))	
	print("b2:\n",sess.run(b2))
 
plt.scatter(X[:,0], X[:,1], c=np.squeeze(Y_c))
plt.contour(xx, yy, probs, levels=[.5])
plt.show()
 
 
# 定义反向传播方法:包含正则化
train_step = tf.train.AdamOptimizer(0.0001).minimize(loss_total)
 
with tf.Session() as sess:
	init_op = tf.global_variables_initializer()
	sess.run(init_op)
	STEPS = 40000
	for i in range(STEPS):
		start = (i*BATCH_SIZE) % 300
		end = start + BATCH_SIZE
		sess.run(train_step, feed_dict={x: X[start:end], y_:Y_[start:end]})
		if i % 2000 == 0:
			loss_v = sess.run(loss_total, feed_dict={x:X,y_:Y_})
			print("After %d steps, loss is: %f" %(i, loss_v))
 
	xx, yy = np.mgrid[-3:3:.01, -3:3:.01]
	grid = np.c_[xx.ravel(), yy.ravel()]
	probs = sess.run(y, feed_dict={x:grid})
	probs = probs.reshape(xx.shape)
	print("w1:\n",sess.run(w1))
	print("b1:\n",sess.run(b1))
	print("w2:\n",sess.run(w2))
	print("b2:\n",sess.run(b2))
 
plt.scatter(X[:,0], X[:,1], c=np.squeeze(Y_c)) 
plt.contour(xx, yy, probs, levels=[.5])
plt.show()

执行代码,效果如下:

首先,数据集实现可视化,x02 + x12 < 2的点显示红色, x02 + x122 的点显示蓝色,如图所示:
在这里插入图片描述
接着,执行无正则化的训练过程,把红色的点和蓝色的点分开,生成曲线如下图所示:
在这里插入图片描述
最后,执行有正则化的训练过程,把红色的点和蓝色的点分开,生成曲线如下图所示:
在这里插入图片描述
对比无正则化与有正则化模型的训练结果,可看出有正则化模型的拟合曲线平滑,模型具有更好的泛化能力。
神经网络搭建八股

前向传播:由输入到输出,搭建完整的网络结构 描述前向传播的过程需要定义三个函数:

def forward(x, regularizer):

w=

b=

y=

return y

第一个函数 forward()完成网络结构的设计,从输入到输出搭建完整的网络结构,实现前向传播过程。该函数中,参数x为输入,regularizer为正则化权重,返回值为预测或分类结果y。

def get_weight(shape, regularizer):           
w = tf.Variable() 
tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(regularizer)(w))  
return w

第二个函数get_weight()对参数w设定。该函数中,参数shape表示参数w的形状,regularizer 表示正则化权重,返回值为参数w。其中,tf.variable()给w赋初值,tf.add_to_collection()表示将参数w正则化损失加到总损失losses中。

defget_bias(shape):

b =tf.Variable( )

return b

第三个函数get_bias()对参数b进行设定。该函数中,参数shape表示参数b的形状,返回值为参数b。其中,tf.variable()表示给w赋初值。

反向传播:训练网络,优化网络参数,提高模型准确性。

def backward( ):

x= tf.placeholder( )

y_ = tf.placeholder( )

y =forward.forward(x, REGULARIZER)

global_step = tf.Variable(0,trainable=False)

loss =

函数 backward()中,placeholder()实现对数据集x和标准答案y_占位,forward.forward()实现前向传播的网络结构,参数global_step表示训练轮数,设置为不可训练型参数。在训练网络模型时,常将正则化、指数衰减学习率和滑动平均这三个方法作为模型优化方法。

在Tensorflow中,正则化表示为:首先,计算预测结果与标准答案的损失值

①MSE: y 与 y_的差距(loss_mse) =tf.reduce_mean(tf.square(y-y_))

②交叉熵:ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_, 1))

y与 y_的差距(cem) = tf.reduce_mean(ce)

③自定义:y 与 y_的差距

其次,总损失值为预测结果与标准答案的损失值加上正则化项

loss = y 与 y_的差距 +tf.add_n(tf.get_collection(‘losses’))

在Tensorflow中,指数衰减学习率表示为:

learning_rate= tf.train.exponential_decay(LEARNING_RATE_BASE, global_step, 
                            数据集总样本数 / BATCH_SIZE,
                            LEARNING_RATE_DECAY,staircase=True)
train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)

在Tensorflow中,滑动平均表示为:

ema=tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)  
ema_op =ema.apply(tf.trainable_variables())
with tf.control_dependencies([train_step, ema_op]):          
train_op = tf.no_op(name='train')

其中,滑动平均和指数衰减学习率中的global_step为同一个参数。

用with结构初始化所有参数

with tf.Session() as sess:        
 init_op =tf.global_variables_initializer()       
    sess.run(init_op)  for i inrange(STEPS):
     sess.run(train_step, feed_dict={x:   , y_:  })            
        if i % 轮数 == 0:
          print

其中,with结构用于初始化所有参数信息以及实现调用训练过程,并打印出loss值。

判断python运行文件是否为主文件

if name==‘main’:

backward()

该部分用来判断python运行的文件是否为主文件。若是主文件,则执行backword()函数。 例如: 用300个符合正态分布的点X[x0, x1]作为数据集,根据点X[x0, x1]的不同进行标注Y_,将数据集标注为红色和蓝色。标注规则为:当x02 + x12 < 2 时,y_=1,点X标注为红色;当x02 + x12 2 时,y_=0,点X标注为蓝色。我们加入指数衰减学习率优化效率,加入正则化提高泛化性,并使用模块化设计方法,把红色点和蓝色点分开。

代码总共分为三个模块:生成数据集(generateds.py)、前向传播(forward.py)、反向传播(backward.py)。

①生成数据集的模块(opt_generateds.py)

# 0.导入模块 ,生成模拟数据集
import numpy as np
import matplotlib.pyplot as plt
seed = 2 
def generateds():
	# 基于seed产生随机数
	rdm = np.random.RandomState(seed)
	# 随机数返回300行2列的矩阵,表示300组坐标点(x0,x1)作为输入数据集
	X = rdm.randn(300,2)
	# 从X这个300行2列的矩阵中取出一行,判断如果两个坐标的平方和小于2,给Y赋值1,其余赋值0
	# 作为输入数据集的标签(正确答案)
	Y_ = [int(x0*x0 + x1*x1 <2) for (x0,x1) in X]
	# 遍历Y中的每个元素,1赋值'red'其余赋值'blue',这样可视化显示时人可以直观区分
	Y_c = [['red' if y else 'blue'] for y in Y_]
	# 对数据集X和标签Y进行形状整理,第一个元素为-1表示跟随第二列计算,第二个元素表示多少列,可见X为两列,Y为1列
	X = np.vstack(X).reshape(-1,2)
	Y_ = np.vstack(Y_).reshape(-1,1)
	return X, Y_, Y_c	
# 用plt.scatter画出数据集X各行中第0列元素和第1列元素的点即各行的(x0,x1),用各行Y_c对应的值表示颜色(c是color的缩写) 
# plt.scatter(X[:,0], X[:,1], c=np.squeeze(Y_c)) 
# plt.show()

②前向传播模块(opt_forward.py)

# 0.导入模块 ,生成模拟数据集
import tensorflow as tf
 
# 定义神经网络的输入、参数和输出,定义前向传播过程 
def get_weight(shape, regularizer):
	w = tf.Variable(tf.random_normal(shape), dtype=tf.float32)
	tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))
	return w
 
def get_bias(shape):  
    b = tf.Variable(tf.constant(0.01, shape=shape)) 
    return b
	
def forward(x, regularizer):
	
	w1 = get_weight([2,11], regularizer)	
	b1 = get_bias([11])
	y1 = tf.nn.relu(tf.matmul(x, w1) + b1)
 
	w2 = get_weight([11,1], regularizer)
	b2 = get_bias([1])
	y = tf.matmul(y1, w2) + b2 
	
	return y

③反向传播模块(opt_backward.py)

# 0.导入模块 ,生成模拟数据集
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import opt_generateds
import opt_forward
 
STEPS = 40000
BATCH_SIZE = 30 
LEARNING_RATE_BASE = 0.001
LEARNING_RATE_DECAY = 0.999
REGULARIZER = 0.01
 
def backward():
	x = tf.placeholder(tf.float32, shape=(None, 2))
	y_ = tf.placeholder(tf.float32, shape=(None, 1))
 
	X, Y_, Y_c = opt_generateds.generateds()
 
	y = opt_forward.forward(x, REGULARIZER)
	
	global_step = tf.Variable(0,trainable=False)	
 
	learning_rate = tf.train.exponential_decay(
		LEARNING_RATE_BASE,
		global_step,
		300/BATCH_SIZE,
		LEARNING_RATE_DECAY,
		staircase=True)
 
 
	# 定义损失函数
	loss_mse = tf.reduce_mean(tf.square(y-y_))
	loss_total = loss_mse + tf.add_n(tf.get_collection('losses'))
	
	# 定义反向传播方法:包含正则化
	train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss_total)
 
	with tf.Session() as sess:
		init_op = tf.global_variables_initializer()
		sess.run(init_op)
		for i in range(STEPS):
			start = (i*BATCH_SIZE) % 300
			end = start + BATCH_SIZE
			sess.run(train_step, feed_dict={x: X[start:end], y_:Y_[start:end]})
			if i % 2000 == 0:
				loss_v = sess.run(loss_total, feed_dict={x:X,y_:Y_})
				print("After %d steps, loss is: %f" %(i, loss_v))
 
		xx, yy = np.mgrid[-3:3:.01, -3:3:.01]
		grid = np.c_[xx.ravel(), yy.ravel()]
		probs = sess.run(y, feed_dict={x:grid})
		probs = probs.reshape(xx.shape)
	
	plt.scatter(X[:,0], X[:,1], c=np.squeeze(Y_c)) 
	plt.contour(xx, yy, probs, levels=[.5])
	plt.show()
	
if __name__=='__main__':
	backward()

运行结果如下:
在这里插入图片描述
由运行结果可见,程序使用模块化设计方法,加入指数衰减学习率,使用正则化后,红色点和蓝色点的分割曲线相对平滑,效果变好。

二、全连接网络基础

MNIST数据集

MNIST数据集:MNIST数据集是机器学习领域中非常经典的一个数据集,由60000个训练样本和10000个测试样本组成,每个样本都是一张28 * 28像素的灰度手写数字图片。

下载
官方网站 http://yann.lecun.com/exdb/mnist/
一共4个文件,训练集、训练集标签、测试集、测试集标签

共有7万张图片。其中6万张用于训练神经网络,1万张用于测试神经网络。

每张图片是一个28*28像素点的0~9的手写数字图片。

黑底白字。黑底用0表示,白字用0~1之间的浮点数表示,越接近1,颜色越百。

我们把784个像素点组成一个长度为784的一维数组,这个一维数据就是我们要喂入神经网络的输入特征。MNIST数据集还提供了每张图片对应的标签,以一个长度为10的一维数组给出。

例如: 一张数字手写体图片变成长度为784的一维数组[0.0.0.0.0.231 0.235 0.459 ……0.219 0.0.0.0.]输入神经网络。该图片对应的标签为[0.0.0.0.0.0.1.0.0.0],标签中索引号为6的元素为1,表示是数字6出现的概率为100%,则该图片对应的识别结果是6。

使用input_data模块中的read_data_sets()函数加载mnist数据集:

from tensorflow.examples.tutorials.mnist import input_data  
mnist = input_data.read_data_sets(./data/,one_hot=True) 

在 read_data_sets()函数中有两个参数,第一个参数表示数据集存放路径,第二个参数表示数据集的存取形式。当第二个参数为Ture时,表示以独热码形式存取数据集。read_data_sets()函数运行时,会检查指定路径内是否已经有数据集,若指定路径中没有数据集,则自动下载,并将mnist数据集分为训练集train、验证集validation和测试集test存放。

返回mnist数据集中训练集train、验证集validation和测试集test样本数

在Tensorflow中用以下函数返回子集样本数:

①返回训练集train样本数

print “train data size:”,mnist.train.num_examples

输出结果:train data size:55000

②返回验证集validation样本数

print “validationdata size:”,mnist.validation.num_examples

输出结果:validationdata size:5000

③返回测试集test样本数

print “test data size:”,mnist.test.num_examples

输出结果:test data size:10000

使用train.labels函数返回mnist数据集标签

例如: 在mnist数据集中,若想要查看训练集中第0张图片的标签,则使用如下函数

mnist.train.labels[0] 输出结果:array([0.,0.,0.,0.,0.,0.,1.,0.,0.,0])

使用train.images函数返回mnist数据集图片像素值

例如: 在 mnist 数据集中,若想要查看训练集中第 0 张图片像素值,则使用如下函数

mnist.train.images[0]

输出结果:

array([0. ,0. ,0. ,
0. ,0. ,0. ,
0. ,0. ,0. ,
… … …])

使用mnist.train.next_batch()函数将数据输入神经网络

例如:

BATCH_SIZE = 200

xs,ys = mnist.train.next_batch(BATCH_SIZE)

print “xsshape:”,xs.shape

print “ys shape:”,ys.shape

输出结果:xs.shape(200,784)

输出结果:ys.shape(200,10)

其中,mnist.train.next_batch()函数包含一个参数BATCH_SIZE,表示随机从训练集中抽取BATCH_SIZE个样本输入神经网络,并将样本的像素值和标签分别赋给xs和ys。在本例中,BATCH_SIZE设置为200,表示一次将200个样本的像素值和标签分别赋值给xs和ys,故xs的形状为(200,784),对应的ys的形状为(200,10)。

实现“Mnist数据集手写数字识别”的常用函数:

①tf.get_collection(“”)函数表示从 collection 集合中取出全部变量生成一个列表。

②tf.add( )函数表示将参数列表中对应元素相加。

例如:x=tf.constant([[1,2],[1,2]]) y=tf.constant([[1,1],[1,2]]) z=tf.add(x,y) print z

输出结果:[[2,3],[2,4]]

③tf.cast(x,dtype)函数表示将参数x转换为指定数据类型。

例如:

A = tf.convert_to_tensor(np.array([[1,1,2,4], [3,4,8,5]]))

print A.dtype b = tf.cast(A, tf.float32) print b.dtype

结果输出:

<dtype: ‘int64’>

<dtype: ‘float32’>

从输出结果看出,将矩阵A由整数型变为32位浮点型。

④tf.equal( )函数表示对比两个矩阵或者向量的元素。若对应元素相等,则返回True;若对应元素不相等,则返回False。

例如:

A = [[1,3,4,5,6]] B =[[1,3,4,3,2]]

with tf.Session( ) as sess:

print(sess.run(tf.equal(A, B)))

输出结果:[[True True True False False]]

在矩阵A和B中,第1、2、3个元素相等,第4、5个元素不等,故输出结果中,第1、2、3个元素取值为True,第4、5个元素取值为False。

⑤tf.reduce_mean(x,axis)函数表示求取矩阵或张量指定维度的平均值。若不指定第二个参数,则在所有元素中取平均值;若指定第二个参数为0,则在第一维元素上取平均值,即每一列求平均值;若指定第二个参数为1,则在第二维元素上取平均值,即每一行求平均值。

例如:

x = [[1., 1.][2., 2.]]

print(tf.reduce_mean(x))

输出结果:1.5

print(tf.reduce_mean(x, 0))

输出结果:[1.5, 1.5]

print(tf.reduce_mean(x, 1))

输出结果:[1., 1.]

⑥tf.argmax(x,axis)函数表示返回指定维度axis下,参数x中最大值索引号。

例如:

在tf.argmax([1,0,0],1)函数中,axis为1,参数x为[1,0,0],表示在参数x

的第一个维度取最大值对应的索引号,故返回0。

⑦os.path.join()函数表示把参数字符串按照路径命名规则拼接。

例如:

import os os.path.join(’/hello/’,‘good/boy/’,‘doiido’)

输出结果:’/hello/good/boy/doiido’

⑧字符串.split( )函数表示按照指定“拆分符”对字符串拆分,返回拆分列表。

例如:’./model/mnist_model-1001’.split(’/’)[-1].split(’-’)[-1]

在该例子中,共进行两次拆分。第一个拆分符为‘/’,返回拆分列表,并提取列表中索引为-1的元素即倒数第一个元素;第二个拆分符为‘-’,返回拆分列表,并提取列表中索引为-1的元素即倒数第一个元素,故函数返回值为1001。

⑨tf.Graph( ).as_default( )函数表示将当前图设置成为默认图,并返回一个上下文管理器。该函数一般与with关键字搭配使用,应用于将已经定义好的神经网络在计算图中复现。

例如:

with tf.Graph().as_default() as g,表示将在Graph()内定义的节点加入到计算图g中。

神经网络模型的保存

在反向传播过程中,一般会间隔一定轮数保存一次神经网络模型,并产生三个文件(保存当前图结构的.meta文件、保存当前参数名的.index文件、保存当前参数的.data文件),在Tensorflow中如下表示:

saver = tf.train.Saver()         
with tf.Session() as sess:       
    for i in range(STEPS):        
        if i % 轮数 == 0:         
           saver.save(sess, os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step=global_step)

其中,tf.train.Saver()用来实例化saver对象。上述代码表示,神经网络每循环规定的轮数,将神经网络模型中所有的参数等信息保存到指定的路径中,并在存放网络模型的文件夹名称中注明保存模型时的训练轮数。

神经网络模型的加载 在测试网络效果时,需要将训练好的神经网络模型加载,在Tensorflow中这样表示:

with tf.Session() as sess:
    ckpt =tf.train.get_checkpoint_state(存储路径)     
        if ckpt and ckpt.model_checkpoint_path:
             saver.restore(sess,ckpt.model_checkpoint_path)

在with结构中进行加载保存的神经网络模型,若ckpt和保存的模型在指定路径中存在,则将保存的神经网络模型加载到当前会话中。

加载模型中参数的滑动平均值

在保存模型时,若模型中采用滑动平均,则参数的滑动平均值会保存在相应文件中。通过实例化saver对象,实现参数滑动平均值的加载,在Tensorflow中如下表示:

ema = tf.train.ExponentialMovingAverage(滑动平均基数)
ema_restore = ema.variables_to_restore()         
saver = tf.train.Saver(ema_restore)

神经网络模型准确率评估方法在网络评估时,一般通过计算在一组数据上的识别准确率,评估神经网络的效果。

在Tensorflow中这样表示:

correct_prediction= tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy =tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

在上述中,y 表示在一组数据(即batch_size 个数据)上神经网络模型的预测结果,y 的形状为[batch_size,10],每一行表示一张图片的识别结果。通过tf.argmax()函数取出每张图片对应向量中最大值元素对应的索引值,组成长度为输入数据batch_size个的一维数组。通过tf.equal()函数判断预测结果张量和实际标签张量的每个维度是否相等,若相等则返回True,不相等则返回False。通过 tf.cast()函数将得到的布尔型数值转化为实数型,再通过tf.reduce_mean()函数求平均值,最终得到神经网络模型在本组数据上的准确率。
模块化搭建神经网络

神经网络八股包括前向传播过程、反向传播过程、反向传播过程中用到的正则化、指数衰减学习率、滑动平均方法的设置、以及测试模块。

前向传播过程(forward.py)

前向传播过程完成神经网络的搭建,结构如下:

def forward(x, regularizer):
def forward(x, regularizer):
    w=  
    b=
    y= 
return y 
def get_weight(shape, regularizer): 
def get_bias(shape):          

前向传播过程中,需要定义神经网络中的参数w和偏置b,定义由输入到输出的网络结构。通过定义函数get_weight()实现对参数w的设置,包括参数w的形状和是否正则化的标志。同样,通过定义函数get_bias()实现对偏置b的设置。

反向传播过程(backword.py)

反向传播过程完成网络参数的训练,结构如下:

def backward( mnist ):
x  = tf.placeholder(dtype, shape )
y_ = tf.placeholder(dtype, shape )
#定义前向传播函数
y  = forward( )                  
global_step = 
loss = 
train_step =tf.train.GradientDescentOptimizer(learning_rate).
minimize(loss,global_step=global_step)
#实例化saver对象
saver = tf.train.Saver() with tf.Session() as sess:  
#初始化所有模型参数      
tf.initialize_all_variables().run()  
#训练模型
  for i in range(STEPS):
     sess.run(train_step,feed_dict={x:   , y_:   })      
         if i % 轮数 == 0:          
            print
          saver.save(   )

反向传播过程中,用tf.placeholder(dtype, shape)函数实现训练样本x和样本标签y_占位,函数参数dtype表示数据的类型,shape表示数据的形状;y表示定义的前向传播函数forward;loss表示定义的损失函数,一般为预测值与样本标签的交叉熵(或均方误差)与正则化损失之和;train_step表示利用优化算法对模型参数进行优化,常用优化算法GradientDescentOptimizer、AdamOptimizer、MomentumOptimizer算法,在上述代码中使用的GradientDescentOptimizer优化算法。接着实例化saver对象,其中利用tf.initialize_all_variables().run()函数实例化所有参数模型,利用sess.run( )函数实现模型的训练优化过程,并每间隔一定轮数保存一次模型。

正则化、指数衰减学习率、滑动平均方法的设置

①正则化项regularization

当在前向传播过程中即forward.py文件中,设置正则化参数regularization为 1时,则表明在反向传播过程中优化模型参数时,需要在损失函数中加入正则化项。 结构如下:

首先,需要在前向传播过程即forward.py文件中加入

if regularizer !=None: tf.add_to_collection(‘losses’, tf.contrib.layers.l2_regularizer(regularizer)(w))

其次,需要在反向传播过程即backword.py文件中加入

ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_, 1)) cem = tf.reduce_mean(ce)

loss = cem + tf.add_n(tf.get_collection(‘losses’))

其中,tf.nn.sparse_softmax_cross_entropy_with_logits()表示softmax()函数与交叉熵一起使用。

②指数衰减学习率 在训练模型时,使用指数衰减学习率可以使模型在训练的前期快速收敛接近较优解,又可以保证模型在训练后期不会有太大波动。运用指数衰减学习率,需要在反向传播过程即backword.py文件中加入:

learning_rate = tf.train.exponential_decay( LEARNING_RATE_BASE, global_step,

LEARNING_RATE_STEP, LEARNING_RATE_DECAY, staircase=True)

③滑动平均 在模型训练时引入滑动平均可以使模型在测试数据上表现的更加健壮。

需要在反向传播过程即backword.py文件中加入:

ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)

ema_op = ema.apply(tf.trainable_variables()) with tf.control_dependencies([train_step, ema_op]):

train_op = tf.no_op(name=‘train’)

测试过程(test.py)

当神经网络模型训练完成后,便可用于测试数据集,验证神经网络的性能。结构

如下: 首先,制定模型测试函数test()

def test( mnist ):  
with tf.Graph( ).as_default( ) as g:
#给x y_占位
x = tf.placeholder(dtype,shape)     
y_ = tf.placeholder(dtype,shape)  #前向传播得到预测结果y
y = mnist_forward.forward(x,None)  #前向传播得到y
#实例化可还原滑动平均的saver
ema =tf.train.ExponentialMovingAverage(滑动衰减率)
    ema_restore =ema.variables_to_restore()    
    saver =tf.train.Saver(ema_restore)
#计算正确率
correct_prediction =tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy =tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
while True:                         
       with tf.Session() as sess:
         #加载训练好的模型
         ckpt = tf.train.get_checkpoint_state(存储路径)
        #如果已有ckpt模型则恢复  
                if ckpt andckpt.model_checkpoint_path: 
                    #恢复会话                    
                        saver.restore(sess, ckpt.model_checkpoint_path) 
                    #恢复轮数                    
                          global_ste = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]                          
                    #计算准确率 
                          accuracy_score = sess.run(accuracy,feed_dict={x:测试数据, y_:测试数据标签 })                
                    # 打印提示   
                         print("After %straining step(s), test accuracy=%g" % (global_step, accuracy_score))                  
                     #如果没有模型   
                          else:
                   print('No checkpoint file found') #模型不存在提示                                  
                   return     

其次,制定main()函数 def main():

#加载测试数据集   
mnist =input_data.read_data_sets("./data/", one_hot=True)
#调用定义好的测试函数test()    
   test(mnist) if __name__ == '__main__':    
   main()

通过对测试数据的预测得到准确率,从而判断出训练出的神经网络模型的性能好坏。当准确率低时,可能原因有模型需要改进,或者是训练数据量太少导致过拟合。

5.3 手写数字识别准确率输出

实现手写体mnist数据集的识别任务,共分为三个模块文件,分别是描述网络结构的前向传播过程文件(mnist_forward.py)、描述网络参数优化方法的反向传播过程文件(mnist_backward.py)、验证模型准确率的测试过程文件(mnist_test.py)。

前向传播过程文件(mnist_forward.py)

在前向传播过程中,需要定义网络模型输入层个数、隐藏层节点数、输出层个数,定义网络参数w、偏置b,定义由输入到输出的神经网络架构。

实现手写体mnist数据集的识别任务前向传播过程如下:

import tensorflow as tf

INPUT_NODE = 784 # 神经网络的输入节点是784个,正好是28*28*1
OUTPUT_NODE = 10 # 输出点
LAYER1_NODE = 500 # 隐藏层节点的个数
# 得到我们的权值矩阵函数
def get_weight(shape,regularizer):
    w = tf.Variable(tf.truncated_normal(shape,stddev = 0.1))
    '''如果使用正则化,则将每一个w的正则化记录到总loss中的这一行代码'''
    if regularizer !=None: tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(regularizer)(w))
    return w
# 得到偏置项函数
def get_bias(shape):
    b = tf.Variable(tf.zeros(shape))
    return b
# 定义前向传播的函数
def forward(x,regularizer):
    w1 = get_weight([INPUT_NODE,LAYER1_NODE],regularizer)
    b1 = get_bias([LAYER1_NODE])
    y1 = tf.nn.relu(tf.matmul(x,w1)+b1)

    w2 = get_weight([LAYER1_NODE,OUTPUT_NODE],regularizer)
    b2 = get_bias([OUTPUT_NODE])
    y = tf.matmul(y1,w2)+b2
    return y

由上述代码可知,在前向传播过程中,规定网络输入结点为 784 个(代表每张输入图片的像素个数), 隐藏层节点 500 个,输出节点 10 个(表示输出为数字 0-9的十分类)。 由输入层到隐藏层的参数 w1 形状为[784,500],由隐藏层到输出层的参数 w2 形状为[500,10],参数满足截断正态分布,并使用正则化,将每个参数的正则化损失加到总损失中。由输入层到隐藏层的偏置 b1 形状为长度为 500的一维数组, 由隐藏层到输出层的偏置 b2 形状为长度为 10 的一维数组,初始化值为全 0。 前向传播结构第一层为输入 x 与参数 w1 矩阵相乘加上偏置 b1,再经过 relu 函数,得到隐藏层输出 y1。 前向传播结构第二层为隐藏层输出 y1 与参数 w2 矩阵相乘加上偏置 b2,得到输出 y。由于输出 y 要经过 softmax 函数,使其符合概率分布,故输出 y 不经过 relu 函数。

反向传播过程文件(mnist_backward.py)

#反向传播
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data  #导入模块
import mnist_forward
import os

BATCH_SIZE = 200  #一次性喂入神经网络的数据大小
LEARNING_RATE_BASE = 0.1   #初始的学习率
LEARNING_RATE_DECAY = 0.99  #衰减率
REGULARIZER = 0.0001 #正则化参数
STEPS = 50000
MOVING_AVERAGE_DECAY = 0.99
MODEL_SAVE_PATH = "./MODEL/"
#MODEL_SAVE_PATH = "./home/lyw/eclipse-workspace/testpython1/test"
#MODEL_SAVE_PATH = "./model/"
MODEL_NAME = "mnist_model"#模型的保存的文件名
#反向传播,输入mnist
def backward(mnist):
    #输入x,y_进行占位
    x = tf.placeholder(tf.float32,[None,mnist_forward.INPUT_NODE])
    y_ = tf.placeholder(tf.float32,[None,mnist_forward.OUTPUT_NODE])
    #首先进行前向传播
    y = mnist_forward.forward(x,REGULARIZER)
    '''轮数计数器赋值0,设定为不可训练'''
    global_step = tf.Variable(0,trainable = False)
    '''定义损失函数,将softmax和交叉商协同使用'''
    ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels= tf.argmax(y_,1))
    cem = tf.reduce_mean(ce)#对向量求均值
    loss = cem+tf.add_n(tf.get_collection('losses'))#将参数w的正则化加入到总loss中
    '''函数实现指数衰减学习率'''
    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)
    '''采用滑动平均的方法进行参数的更新'''
    ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
    ema_op = ema.apply(tf.trainable_variables())
    with tf.control_dependencies([train_step,ema_op]):
        train_op = tf.no_op(name='train')
    
    
    '''保存模型'''
    saver = tf.train.Saver()#实例化saver对象
    

    with tf.Session() as sess:
        init_op = tf.global_variables_initializer()
        sess.run(init_op)

        for i in range(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})
            if i%1000 ==0:
                #每1000轮打印出当前的loss值
                print("After %d training step(s),loss on training batchis %g" %(step,loss_value))
                #循环1000轮保存模型到当前会话
                saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step = global_step)


def main():
    mnist = input_data.read_data_sets("./data",one_hot = True)
    backward(mnist)

if __name__ =='__main__':
    main()

由上述代码可知,在反向传播过程中,首先引入 tensorflow、 input_data、前向传播 mnist_forward 和 os 模块,定义每轮喂入神经网络的图片数、初始学习率、学习率衰减率、正则化系数、训练轮数、模型保存路径以及模型保存名称等相关信息。 在反向传播函数 backword 中, 首先读入 mnist,用 placeholder 给训练数据 x 和标签 y_占位,调用 mnist_forward 文件中的前向传播过程 forword()函数,并设置正则化,计算训练数据集上的预测结果 y,并给当前计算轮数计数器赋值,设定为不可训练类型。 接着, 调用包含所有参数正则化损失的损失函数loss, 并设定指数衰减学习率 learning_rate。然后,使用梯度衰减算法对模型优化,降低损失函数,并定义参数的滑动平均。最后,在 with 结构中,实现所有参数初始化,每次喂入 batch_size 组(即 200 组)训练数据和对应标签,循环迭代 steps 轮,并每隔 1000 轮打印出一次损失函数值信息,并将当前会话加载到指定路径。 最后,通过主函数 main(),加载指定路径下的训练数据集,并调用规定的 backward()函数训练模型。

反向传播文件下的运行结果如下:

(tensorflow) zlt@zlt-virtual-machine:~/download$ /home/zlt/anaconda3/envs/tensorflow/bin/python /home/zlt/download/MyTfTest/mnist_backward.py
Extracting ./data/train-images-idx3-ubyte.gz
Extracting ./data/train-labels-idx1-ubyte.gz
Extracting ./data/t10k-images-idx3-ubyte.gz
Extracting ./data/t10k-labels-idx1-ubyte.gz
After 1 training step(s),loss on training batchis 3.38109
After 1001 training step(s),loss on training batchis 0.395644
After 2001 training step(s),loss on training batchis 0.231999
After 3001 training step(s),loss on training batchis 0.197062
After 4001 training step(s),loss on training batchis 0.210527
After 5001 training step(s),loss on training batchis 0.213639
After 6001 training step(s),loss on training batchis 0.22198
After 7001 training step(s),loss on training batchis 0.17473
After 8001 training step(s),loss on training batchis 0.193039
After 9001 training step(s),loss on training batchis 0.181347
After 10001 training step(s),loss on training batchis 0.168386
After 11001 training step(s),loss on training batchis 0.171536
After 12001 training step(s),loss on training batchis 0.193639
After 13001 training step(s),loss on training batchis 0.178412
After 14001 training step(s),loss on training batchis 0.161824
After 15001 training step(s),loss on training batchis 0.154334
After 16001 training step(s),loss on training batchis 0.153975
After 17001 training step(s),loss on training batchis 0.150825
After 18001 training step(s),loss on training batchis 0.15213
After 19001 training step(s),loss on training batchis 0.156512
After 20001 training step(s),loss on training batchis 0.151868
After 21001 training step(s),loss on training batchis 0.188921
After 22001 training step(s),loss on training batchis 0.140175
After 23001 training step(s),loss on training batchis 0.136725
After 24001 training step(s),loss on training batchis 0.140219
After 25001 training step(s),loss on training batchis 0.142308
After 26001 training step(s),loss on training batchis 0.1352
After 27001 training step(s),loss on training batchis 0.138595
After 28001 training step(s),loss on training batchis 0.131064
After 29001 training step(s),loss on training batchis 0.149518
After 30001 training step(s),loss on training batchis 0.131991
After 31001 training step(s),loss on training batchis 0.131483
After 32001 training step(s),loss on training batchis 0.130529
After 33001 training step(s),loss on training batchis 0.133893
After 34001 training step(s),loss on training batchis 0.131765
After 35001 training step(s),loss on training batchis 0.141108
After 36001 training step(s),loss on training batchis 0.129401
After 37001 training step(s),loss on training batchis 0.127964
After 38001 training step(s),loss on training batchis 0.135317
After 39001 training step(s),loss on training batchis 0.124418
After 40001 training step(s),loss on training batchis 0.124659
After 41001 training step(s),loss on training batchis 0.12862
After 42001 training step(s),loss on training batchis 0.129189
After 43001 training step(s),loss on training batchis 0.133749
After 44001 training step(s),loss on training batchis 0.129562
After 45001 training step(s),loss on training batchis 0.126443
After 46001 training step(s),loss on training batchis 0.128812
After 47001 training step(s),loss on training batchis 0.124785
After 48001 training step(s),loss on training batchis 0.130655
After 49001 training step(s),loss on training batchis 0.124701

在这里插入图片描述
测试过程文件(mnist_test.py)

#coding:utf-8
'''
当训练完模型后, 给神经网络模型输入测试集验证网络的准确性和泛化性。注意,
所用的测试集和训练集是相互独立的。
实现手写体 mnist 数据集的识别任务测试传播过程如下:
'''
import time
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_forward
import mnist_backward
TEST_INTERVAL_SECS = 5
#制定模型测试函数
def test(mnist):
    with tf.Graph().as_default() as g:
        x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])
        y_ = tf.placeholder(tf.float32, [None, mnist_forward.OUTPUT_NODE])
        # 前向传播得到预测结果 y
        y = mnist_forward.forward(x, None)
#在保存模型时,若模型中采用滑动平均,则参数的滑动平均值会保存在相应文件中。 通过实例化 saver 对象, 实现参数滑动平均值的加载
        ema = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
        ema_restore = ema.variables_to_restore()
        saver = tf.train.Saver(ema_restore)
#在网络评估时,一般通过计算在一组数据上的识别准确率, 评估神经网络的效果
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#reduce_mean(x,axis)函数表示求取矩阵或张量指定维度的平均值
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
 
        while True:
            with tf.Session() as sess:
                # 加载训练好的模型
                ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)#存储路径
                # 如果已有 ckpt 模型则恢复
                if ckpt and ckpt.model_checkpoint_path:
                    # 恢复会话
                    saver.restore(sess, ckpt.model_checkpoint_path)
                    ##恢复轮数,字符串.split( )函数表示按照指定“拆分符” 对字符串拆分, 返回拆分列表
                    global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
                    accuracy_score = sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})#喂入数据计算
                    print("After %s training step(s), test accuracy = %g" % (global_step, accuracy_score))
                else:
                    print('No checkpoint file found')
                    return
            time.sleep(TEST_INTERVAL_SECS)
 
def main():
    #加载数据集,第一个参数表示数据集存放路径, 第二个参数表示数据集的存取形式。当第二个参数为 Ture 时, 表示以独热码形式存取数据集。
    ##read_data_sets()会检查指定路径内是否已经有数据集,若指定路径中没有数据集,则自动下载,并将 mnist 数据集分为训练集 train、验证集 validation 和测试集 test 存放。
    mnist = input_data.read_data_sets("./data/", one_hot=True)
    test(mnist) #调用测试数据集函数
if __name__ == '__main__':
    main()

在上述代码中,首先需要引入 time 模块、 tensorflow、 input_data、前向传播mnist_forward、反向传播 mnist_backward 模块和 os 模块, 并规定程序 5 秒的循环间隔时间。接着,定义测试函数 test(),读入 mnist 数据集,利用 tf.Graph()复现之前定义的计算图,利用 placeholder 给训练数据 x 和标签 y_占位,调用mnist_forward 文件中的前向传播过程 forword()函数,计算训练数据集上的预测结果 y。 接着, 实例化具有滑动平均的 saver 对象,从而在会话被加载时模型中的所有参数被赋值为各自的滑动平均值,增强模型的稳定性,然后计算模型在测试集上的准确率。在 with 结构中,加载指定路径下的 ckpt,若模型存在,则加载出模型到当前对话,在测试数据集上进行准确率验证,并打印出当前轮数下的准确率,若模型不存在,则打印出模型不存在的提示,从而 test()函数完成。通过主函数 main(),加载指定路径下的测试数据集,并调用规定的 test 函数,
进行模型在测试集上的准确率验证。
测试文件下运行结果如下:

(tensorflow) zlt@zlt-virtual-machine:~/download$ /home/zlt/anaconda3/envs/tensorflow/bin/python /home/zlt/download/MyTfTest/mnist_test.py
Extracting ./data/train-images-idx3-ubyte.gz
Extracting ./data/train-labels-idx1-ubyte.gz
Extracting ./data/t10k-images-idx3-ubyte.gz
Extracting ./data/t10k-labels-idx1-ubyte.gz
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787
After 49001 training step(s), test accuracy = 0.9787

在这里插入图片描述
由运行结果可以看出,随着训练轮数的增加, 网络模型的损失函数值在不断降低,并且在测试集上的准确率在不断提升,有较好的泛化能力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在神经网络训练完成后,我们可以使用模型对新的输入数据进行预测。以下是使用 TensorFlow 进行简单神经网络训练和测试的示例代码: ```python import tensorflow as tf # 定义输入数据 x = tf.placeholder(tf.float32, [None, input_size]) # 定义模型参数 W = tf.Variable(tf.zeros([input_size, num_classes])) b = tf.Variable(tf.zeros([num_classes])) # 定义模型 y = tf.nn.softmax(tf.matmul(x, W) + b) # 定义损失函数 y_ = tf.placeholder(tf.float32, [None, num_classes]) cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])) # 定义优化器 train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy) # 训练模型 with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(num_iterations): batch_xs, batch_ys = get_next_batch(train_data, train_labels, batch_size) 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("Accuracy: ", sess.run(accuracy, feed_dict={x: test_data, y_: test_labels})) ``` 在训练完成后,我们可以使用 `sess.run()` 函数来获取模型的输出。例如,如果我们想要对一个新的数据样本进行预测,我们可以将其传递给 `sess.run()` 函数的 `feed_dict` 参数,并获取模型的输出 `y`。下面是一个简单的示例: ```python # 定义要预测的数据 new_data = [[5.1, 3.5, 1.4, 0.2]] # 获取预测结果 prediction = sess.run(y, feed_dict={x: new_data}) # 打印预测结果 print(prediction) ``` 在上面的代码中,我们将 `new_data` 作为输入数据传递给模型,并使用 `sess.run()` 函数获取模型的输出 `y`。然后,我们打印预测结果即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值