前言
使用神经网络解决分类问题主要分为以下4个步骤:
1.提取问题中实体地特征向量作为神经网络地输入。以下假设作为神经网络输入的特征向量可以直接从数据集中获取;
2.定义神经网络的结构,即如何从神经网络的输入得到输出;
3.通过训练数据来调整神经网络中的参数的取值;
4.使用训练好的神经网络来预测未知的数据。
目录
1、深层神经网络的结构,即前向传播算法
2、前向传播算法的tensorflow实现
3、通过Tensorflow训练神经网络模型,反向传播算法
(1)去线性化
(2)softmax回归
(3)损失函数
(4)优化函数及优化遇到的问题
(一)前向传播算法简介
一个最简单的神经元结构的输出就是所有输入的加权和,不同输入的权重就是神经元的参数。神经网络的优化过程就是优化神经元中参数取值的过程。下图为 全连接的神经网络,因为相邻两层之间任意两个节点之间都有连接。由此区别于后续的卷积层。
计算神经网络的前向传播结果需要三部分信息。一部分为神经网络的输入,即特征向量;第二部分为神经网络的连接结构;第三部分为每个神经元中的参数。
将前向传播算法以矩阵乘法的方式表达为:
用tensorflow实现神经网络的前向传播过程为:
a=tf.matmul(x,w1)
y=tf.matmul(a,w2)
(二)神经网络参数与Tensorflow变量
1、声明+初始化矩阵变量:
weights=tf.Variable(tf.random_normal([2,3],stddev=2))
(1)变量声明函数tf.Variable;
(2)随机数生成函数,上面表示产生一个均值为0、标准差为2 的 2乘3 的矩阵。
| 函数名称 | 随机数分布 | 主要参数 |
|---|---|---|
| tf.random_normal | 正态分布 | 平均值、标准差、取值类型 |
| tf.random_uniform | 均匀分布 | 最小、最大取值,取值类型 |
| tf.random_gamma | Gamma分布 | alpha,beta,取值类型 |
(3)常数生成函数
| 函数名称 | 功能 | 样例 |
|---|---|---|
| tf.zeros | 产生全为0的数组 | tf.zeros([2,3],int32) |
| tf.ones | 产生全为1的数组 | tf.ones([2,3],int32) |
| tf.fill | 产生一个全部为给定数字的数组 | tf.fill([2,3],9) |
| tf.constant | 产生一个给定值的常量 | tf.constant([1,2,3]) |
(4)通过其他变量的初始值来初始化新的变量
w2=tf.Variable(weights.initialized_value())
2、实现神经网络的前向传播过程
import tensorflow as tf
#第一步,定义、声明W1,W2,x,a,y变量
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)#初始化w1
sess.run(w2.initializer)#初始化w2
sess.run(y)
print(y)
sess.close()
简化初始化所有的变量
inin_op=tf.global_variables_initializer()
sess.run(inin_op)
(三)通过Tensorflow训练神经网络模型
设置神经网络参数的过程就是神经网络的训练过程。使用监督学习的方式设置神经网络参数需要有一个标注好的训练数据集。监督学习最重要的思想是在已知答案的标注数据集上,模型给出的预测结果要尽可能地接近真实的答案。神经网络优化算法中,最常用的方法是反向传播算法,流程图表示为:
选取的一部分数据为batch。基于预测组织和真实值之间的差距,反向传播算法会相应更新神经网络参数的取值,使得batch上神经网络的预测结果和真实答案更加接近。
具体地:
1、 tensorflow提供了placeholder机制用于提供输入数据。
对应于上面程序中,
x=tf.placeholder(tf.float32,shape=(3,2),name="input")
...
print(sess.run(y,feed_dict={x:[[0.7,0.9],[0.1,0.4],[0.5,0.8]]}) #n=3))
2、**函数实现去线性化
每个节点的输出在加权和的基础上做了一个非线性变换。
常见的有ReLU函数f(x)=max(x,0);sigmoid函数f(x)=1/(1+e(-x) );tanh函数f(x)=(1-e(-2x))/(1+e(-2x)).
3、softmax回归
神经网络解决多分类问题时,输出n个节点,对应n个类别。由于损失函数交叉熵函数刻画的是输出向量和期望向量之间概率分布的距离,因而需要预先对神经网络的输出值进行softmax回归,得到每个类别的概率值。
4、损失函数
(1)分类问题:交叉熵
p(x)代表正确答案,q(x)代表预测值。交叉熵判断预测答案和真实答案之间的距离。
cross_entropy=-tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))
tf.clip_by_value(y,1e-10,1.0)将y的值控制在1e-10 和1.0之间。
使用softmax回归之后的交叉熵损失函数:
cross_entropy=tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y) #y表示输出结果,y_为标准答案
(2)回归问题:均方误差MSE
mse=tf.reduce_mean(tf.square(y_ - y)) #y_表示标准答案, y表示输出答案
tips:计算的是一组batches的损失函数,否则容易过拟合!
5、神经网络优化算法
优化算法,表示寻找最优的参数,使得损失函数的值最小。最常用的梯度下降算法:用于优化单个参数的取值
参数梯度:损失函数的导函数,在斜率的方向上下降得最快;学习率:每次参数移动的幅度。
形象化展示:https://www.jianshu.com/p/c7e642877b0e
问题:为何不对损失函数直接求导?
最大收获:
对每一个参数求导,得到的最小值点的集合,对应的损失函数并不一定是全局最小的!
6、优化过程中遇到的问题
(1)解决过拟合问题
正则化方法:在损失函数中加入刻画模型复杂程度的指标。将参数w正则化加入交叉熵数值中,优化函数为
其中,R(w)刻画的是模型的复杂程度,
而表示模型复杂损失在总损失中的比例。
tensorflow表示带正则化的损失函数:
w=tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))
y=tf.matmul(x,w)
loss=tf.reduce_mean(tf.square(y_-y))+tf.contrib.layers.l2_regularizer(lambda )(w)
tips:将正则化损失函数和均方误差损失函数均放到集合里去,然后把集合里的数值都加起来,得到最终的损失函数。
tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(lambda_)(var))#将权重的L2正则化损失加入到“losses”集合中
tf.add_to_collection('losses',mse_loss)#将均方误差损失函数添加到损失集合里去
loss=tf.add_n(tf.get_collection('losses'))#计算所有损失的和,get_collection返回集合中的所有元素
(2)滑动平均模型——辅助梯度下降算法
提供了一个衰减率,用于控制模型更新的速度。
import tensorflow as tf
v1=tf.Variable(0,dtype=tf.float32)
step=tf.Variable(0,trainable=False)#用于动态控制衰减率
ema=tf.train.ExponentialMovingAverage(0.99,step)#定义一个滑动平均的类
# decay=min(decay,(1+step)/(10+step))
maintain_average_op=ema.apply([v1])#定义一个更新变量滑动平均所更新的列表
#shadow_variable=decay*shadow_variable+(1-decay)*variable,decay越大模型越稳定
with tf.Session() as sess:
init_op=tf.global_variables_initializer()
sess.run(init_op)#初始化所有变量
print(sess.run([v1,ema.average(v1)]))
sess.run(tf.assign(v1,5))#更新变量v1的值到5
sess.run(maintain_average_op)#更新v1的滑动平均值
print(sess.run([v1,ema.average(v1)]))
sess.run(tf.assign(step,10000))#更新step的值到10000
sess.run(tf.assign(v1,10))
sess.run(maintain_average_op) # 更新v1的滑动平均值
print(sess.run([v1, ema.average(v1)]))
sess.run(maintain_average_op) # 更新v1的滑动平均值
print(sess.run([v1, ema.average(v1)]))
应用还不明白,在下一节吧。。。
深度神经网络完整程序
import tensorflow as tf
from numpy.random import RandomState
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')
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)
#通过随机数生成一个模拟数据集
rdm=RandomState(1)#生成[0,1]区间的随机数
dataset_size=128
X=rdm.rand(dataset_size,2)
Y=[[int(x1+x2 < 1)]for (x1,x2) in X]#x1+x2之后取整,1表示正样本,0表示负样本
#运行tensorflow程序
with tf.Session() as sess:
init_op=tf.global_variables_initializer()
sess.run(init_op)
print(sess.run(w1))
print(sess.run(w2))
STEPS=5000
for i in range(STEPS):
#每次选取batch_size个样本进行训练(感觉这个逻辑很厉害!!!!!!),所以这批数据要被训练5000/(128/8)次。
start=(i*batch_size) % dataset_size
end= min(start+batch_size,dataset_size)
sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
#每循环1000次计算在所有数据上的交叉熵
if i%1000==0:
total_cross_entropy=sess.run(cross_entropy,feed_dict={x:X,y_:Y})
print("hello%d,hi%g"%(i,total_cross_entropy))
print(sess.run(w1))
print(sess.run(w2))
好啦,睡觉啦~good night!