Tensorflow笔记之【神经网络的优化】

神经元模型

用数学公式表示为f(\sum x_{i} w_{i} + b),其中f为激活函数,模型示意图如下

Tensorflow笔记之【神经网络的优化】_第1张图片

激活函数

引入非线性激活因素,提高模型的表达力,常用的激活函数有relu、sigmoid、tanh

Tensorflow笔记之【神经网络的优化】_第2张图片

其它概念

神经网络的复杂度:可用神经网络的层数和神经网络中待优化参数个数表示;

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

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


损失函数的优化

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

均方误差 说明 n个样本的测试值y与已知答案y_之差的平方和,再求平均值
计算公式 MSE(y\_,y)=\frac{\sum _{i=1}^{n} (y-y\_)^{2}}{n}
程序实

loss_mse = tf.reduce_mean( tf.square ( y_ - y ) )

自定义 说明

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

以商品日销量为例,如果预测销量大于实际销量则会损失成本;如果预测销量小于实际销量则会损失利润。在实际生活中,成本和利润往往是不等价的。因此,需要使用符合该问题的自定义损失函数。

计算公式

自定义损失函数为loss=\sum f(y\_,y)

其中,损失定义成分段函数

f(y\_,y)=\left\{\begin{matrix} PROFIT*(y\_-y) & y<y_\\ COST*(y-y\_) & y>=y\_ \end{matrix}\right.

程序实现

loss = tf.reduce_sum ( tf.where ( tf.greater ( y , y_ ) , COST ( y - y_) , PROFIT ( y_ - y ) ) )

交叉熵 说明 表示两个概率分布之间的距离。交叉熵越大,两个概率分布距离越远,两个概率分布越相异;交叉熵越小,两个概率分布距离越近,两个概率分布越相似。
计算公式 H(y\_,y)=-\sum y\_ * log(y)
程序实现 ce=-tf.reduce_mean(y_ * tf.log( tf.clip_by_value ( y,1e-12,1.0 ) ) )
softmax函数

将n分类的n个输出(y1,y2…yn)变为满足以下概率分布要求的函数:

1.任意一个分类的概率都在0到1之间;

2.所有概率的和为1; 

softmax(y_{i})=\frac{e^{yi}}{\sum_{j=1}^{n} e^{yi}}

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

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

cem = tf.reduce_mean(ce)


学习率的优化

学习率表示每次参数更新的幅度大小,学习率过大会导致待优化的参数在最小值附近波动,不收敛;学习率过小会导致待优化的参数收敛缓慢。在训练过程中,参数的更新向着损失函数梯度下降的方向,更新公式为:w_{n+1}=w_{n}-learning\_rate \triangledown

指数衰减学习率——学习率随着训练轮数变化而动态更新

learning\_rate = LEARNING\_ \ RATE\_ \ BASE \ * LEARNING\_ \ RATE\_ \ DECAY ^{ \frac{global\_ step}{LEARNING\_RATE\_STEP}}

其中,LEARNING_RATE_BASE是学习率初始值;LEARNING_RATE_DECAY是学习率衰减率,在0到1之间;global_step是当前运行轮数,也就是完成了多少个BATCH_SIZE;LEARNING_RATE_STEP是更新一次学习率的轮次间隔,一般为总样本数/BATCH_SIZE

实现步骤:

首先定义一个计数器,记录当前共运行了多少轮

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

然后使用tf的函数实现(staircase为TRUE时,公式中的指数取整数)

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

                                                                     LEARNING_RATE_DECAY, staircase=True/False)

例:指数衰减学习率测试

#coding:utf-8
#设损失函数 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 - 衰减率 ) * 参数

其中,衰减率 = min{ MOVING AVERAGE DECAY , (1+轮数)/(10+轮数) },影子初值=参数初值

Tensortflow中表示为:

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')   #将滑动平均和训练同步运行

 ema.average()    #查看模型中参数的平均值


正则化

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

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

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

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

其中,第二项为正则化结果,计算方法如下:

L1正则化 loss_{L1}=\sum \left | w_{i} \right | loss(w) = tf.contrib.layers.l1_regularizer(REGULARIZER)(w)
L2正则化 loss_{L2}=\sum \left | w_{i} \right | ^{2} loss(w) = tf.contrib.layers.l2_regularizer(REGULARIZER)(w)

用Tensorflow函数实现正则化:

tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w)  #可在生成w时执行

loss = cem + tf.add_n(tf.get_collection('losses'))  #最终的损失函数

例:红蓝点分界线拟合

#coding:utf-8
#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()

过拟合的缓解效果:

Tensorflow笔记之【神经网络的优化】_第3张图片   Tensorflow笔记之【神经网络的优化】_第4张图片

 

你可能感兴趣的:(机器学习,Tensorflow)