目录
- 1、激活函数
- 1.1、sigmoid函数:2端饱和,下面2个函数都要幂运算,运算速度会比较慢
- 1.2、ReLU函数(Rectified Linear Unit,修正线性单元)
- 1.3、PReLU函数(Parameteric Rectified Linear Unit,参数化修正线性单元)
- 1.4、RReLU函数(Randomized Leaky Rectified Linear Unit,随机纠正线性单元):
- 2、鸢尾花分类——实现多层神经网络:
- 3、梯度下降法
- 4、优化
1、激活函数
激活函数:为了模拟非线性问题,又不能使得问题过于复杂,可以设计神经元对输入信号进行线性处理,得到的线性结果再输入非线性激活函数
- 激活函数的特点:包含充分的梯度信息;能够识别阈值
1.1、sigmoid函数:2端饱和,下面2个函数都要幂运算,运算速度会比较慢
1.2、ReLU函数(Rectified Linear Unit,修正线性单元)
- 优点:z>0时,导数=1,缓解了梯度消失问题(只有z≤0时才会饱和);
- 缺点:输出不是以0为均值;z≤0时,梯度=0,神经元死亡(无法更新)(可以使用Leaky-ReLU函数)
1.3、PReLU函数(Parameteric Rectified Linear Unit,参数化修正线性单元)
y = { z z≥0 a z z<0 ,a:可训练参数 y= \begin{cases} z& \text{z≥0}\\ az& \text{z<0 ,a:可训练参数} \end{cases} y={zazz≥0z<0 ,a:可训练参数
1.4、RReLU函数(Randomized Leaky Rectified Linear Unit,随机纠正线性单元):
类比上一个,不同在与
- 训练阶段:z<0部分的斜率是随机分配的,服从均匀分布
- 测试阶段:z<0部分的斜率 是固定的,取训练阶段所有a的平均值
2、鸢尾花分类——实现多层神经网络:
(单层的见机器学习笔记6“鸢尾花数据集——单层前馈型神经网络”)
- 增加一个隐含层并设定隐含层有16个节点
- 从输入层到隐含层:B1的shape=(16,),又因为输入有4个节点(鸢尾花的4个属性),所以W1的shape=(4,16)
- 从隐含层到输出层:因为输出层有3个输出节点,所以B2.shape=(3,),W2.shape=(16,3)
- 隐含层激活函数:relu函数;输出层激活函数:softmax函数;损失函数:交叉熵损失函数
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#读取文件,详见Python笔记10
train_path=tf.keras.utils.get_file("iris.csv", origin=None) #获取文件的绝对路径
df_iris=pd.read_csv(train_path,header=0) #结果是panda的二维数据表
iris=np.array(df_iris) #将二维数据表类型转化为二维数组类型,shape=(150,6),与视频中不一样,索引号为0的是序号
x=iris[:,1:5] #索引号1~4列属性:花瓣长度和宽度,x.shape=(150, 2)
y=iris[:,5] #train_y.shape=(150,)x_svv=np.concatenate((np.stack(x[y=='setosa']), #选取2种花,以及其前2种属性np.stack(x[y=='versicolor']),np.stack(x[y=='virginica'])),axis=0)
y_svv=np.concatenate((np.zeros(np.where(y=='setosa')[0].size), #元组只有一个元素(数组)np.ones(np.where(y=='versicolor')[0].size),2*np.ones(np.where(y=='virginica')[0].size),),axis=0)np.random.seed(612)
iris_rand=np.concatenate((x_svv,np.expand_dims(y_svv,axis=1)),axis=1)
np.random.shuffle(iris_rand) #打乱数组,并选前面120条数据为训练集,后面30条做测试集
x_train=tf.constant(iris_rand[:120,0:4],dtype=tf.float32) #转化为float32张量
y_train=tf.constant(iris_rand[:120,4],dtype=tf.int64) #转化为int32张量
x_test=tf.constant(iris_rand[120:,0:4],dtype=np.float32)
y_test=tf.constant(iris_rand[120:,4],dtype=tf.int64)X_train=x_train-tf.reduce_mean(x_train,axis=0) #中心化, x_train.dtype=dtype('O'),是object
X_test=x_test-tf.reduce_mean(x_test,axis=0)
Y_train=tf.one_hot(y_train,3) #转化为独热编码Y_train.shape=TensorShape([120, 3])
Y_test=tf.one_hot(y_test,3)learn_rate=0.5 #超参数——学习率
iter=50 #迭代次数
display_step=10 #设置每迭代10次输出结果,方便查看
np.random.seed(612)
W1=tf.Variable(np.random.randn(4,16),dtype=tf.float32) #W1列向量,4行16列
B1=tf.Variable(np.zeros([16]),dtype=tf.float32) #B1列向量,长度为16的一维张量
W2=tf.Variable(np.random.randn(16,3),dtype=tf.float32) #W2列向量,16行3列
B2=tf.Variable(np.zeros([3]),dtype=tf.float32) #B2列向量,长度为3的一维张量cce_train=[] #保存交叉熵损失
cce_test=[]
acc_train=[] #保存准确率
acc_test=[]#训练模型
for i in range(0,iter+1):with tf.GradientTape() as tape:#relu函数和softmax函数,Hidden_train是120*16的张量,每行16个元素表示隐含层16个节点(就是输入层的输出端有16个),同理PRED_train是16*3Hidden_train=tf.nn.relu(tf.matmul(X_train,W1)+B1) #shape=TensorShape([120, 16])PRED_train=tf.nn.softmax(tf.matmul(Hidden_train,W2)+B2) #shape=TensorShape([16, 3])Loss_train=tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_true=Y_train, y_pred=PRED_train))Hidden_test=tf.nn.relu(tf.matmul(X_test,W1)+B1) #shape=TensorShape([120, 16])PRED_test=tf.nn.softmax(tf.matmul(Hidden_test,W2)+B2) #shape=TensorShape([16, 3])Loss_test=tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_true=Y_test, y_pred=PRED_test))#准确率,求PRED_train的每一行3个元素的max,即属于对应标签的概率最大,再与真实值y_train比较,求得准确率Accuracy_train=tf.reduce_mean(tf.cast(tf.equal(tf.argmax(PRED_train,axis=1),y_train),tf.float32))Accuracy_test=tf.reduce_mean(tf.cast(tf.equal(tf.argmax(PRED_test,axis=1),y_test),tf.float32)) cce_train.append(Loss_train)cce_test.append(Loss_test)acc_train.append(Accuracy_train)acc_test.append(Accuracy_test)grads=tape.gradient(Loss_train,[W1,B1,W2,B2])W1.assign_sub(learn_rate*grads[0])B1.assign_sub(learn_rate*grads[1])W2.assign_sub(learn_rate*grads[2])B2.assign_sub(learn_rate*grads[3])if i%display_step==0:print("i:%i,\tTrainAcc:%f,TrainLoss:%f\tTestAcc:%f,TestLoss:%f" %(i,Accuracy_train,Loss_train,Accuracy_test,Loss_test))#可视化,图1准确率,图2损失函数
plt.figure(figsize=(10,3))
plt.subplot(121)
plt.plot(cce_train,color="blue",label="train")
plt.plot(cce_test,color="red",label="test")
plt.xlabel("Iteration")
plt.ylabel("Loss")
plt.subplot(122)
plt.plot(acc_train,color="blue",label="train")
plt.plot(acc_test,color="red",label="test")
plt.xlabel("Iteration")
plt.ylabel("Accuracy")
plt.tight_layout() #自动调整子图
plt.show()输出:
i:0, TrainAcc:0.466667,TrainLoss:2.097793 TestAcc:0.266667,TestLoss:2.108944
i:10, TrainAcc:0.933333,TrainLoss:0.204642 TestAcc:0.833333,TestLoss:0.344889
i:20, TrainAcc:0.966667,TrainLoss:0.141266 TestAcc:0.866667,TestLoss:0.294079
i:30, TrainAcc:0.958333,TrainLoss:0.110132 TestAcc:0.833333,TestLoss:0.286544
i:40, TrainAcc:0.966667,TrainLoss:0.090271 TestAcc:0.833333,TestLoss:0.290193
i:50, TrainAcc:0.966667,TrainLoss:0.076929 TestAcc:0.800000,TestLoss:0.305203
3、梯度下降法
批量梯度下降(前面介绍 的梯度下降法就是这个)(Batch Gradient Descent, BGD)
- 每次迭代都使用所有样品来计算偏导数:
- 每一步都是准确地朝着极值点趋近,迭代次数少,但每次迭代的计算量大,训练时间长,因而不适合大规模数据集
- 可以利用向量运算进行并行计算
- 收敛于全局或局部极小值点
随机梯度下降(Stochastic Gradient Descent, SGD):
- 每次迭代只选择一个样本训练模型,直到将所有样本都训练一遍,这叫做“一轮”。一轮后对最后一个样品的误差很少,但是后一个样本更新可能导致对上一个样品的效果变差
- 反复训练多轮,直到神经网络对所有样本的误差足够小
- 参数更新非常频繁,训练轮数多,无法快速收敛
小批量梯度下降(Mini-Batch Gradient Descent, MBGD)
- 也叫小批量随机梯度下降(Mini-Batch SGD)
- 把数据集分为多个小批量,每次迭代使用一个小批量来训练模型,参数更新公式:
- 将训练集划分为多个小批量,每次迭代只选择一个小批量训练模型,直到将所有样本都训练一遍,这叫做“一轮”。(固定数目的小批量=1个样品–>随机梯度下降)需要多轮
- 每次迭代的训练样本数固定,与整个训练集的样本数量无关(假设每个小批量200个样本,那么若有2000个样本就分为10批,若有20000个样本就分为100批)
- 并行,大规模数据集
- 小批量的选取是基于抽样,存在偏差,就好像噪声,一定程度上提高模型的泛化能力
4、优化
- 打乱样品
- 并行时,采用2的幂数作为批量大小,如32、64、128…,可以充分利用处理器资源
- 动态调整学习率:学习率衰减(Learning Rate Decay)/学习率退火(Learning Rate Annealing)
周期性地增大学习率
自适应调整学习率(统一调整各个参数的学习率)
自适应调整每个参数的学习率:
- AdaGrad算法:
先全局学习率η,各个参数的学习率表达式如下,将每次迭代的梯度取平方累加,再加上ε(保证分母非0),再开方,用全局学习率除以这个根号。
学习率随着 迭代次数增加而减少。
当某参数梯度比较大,则学习率衰减比较快(学习率变得更小了),当梯度比较小,则学习率衰减比较慢
η ∑ r = 1 t ( g r a d r ) 2 + ε \dfrac{\eta}{\sqrt{\sum ^t_{r=1}(grad_r)^2+\varepsilon }} ∑r=1t(gradr)2+εη- RMSprop算法和AdaDelta算法是对AdaGrad算法的改进,各个参数的学习率不是单调递减的
- 梯度估计:(如果小批量的样品中含有较多的噪声,那么梯度更新就会十分不稳定
动量梯度下降法(Momentum):
- 动量=质量×速度
- 小球下山模型:下山坡度比较大,那么速度积累比较大,如果坡度比较小甚至坡度上升,那么小球速度就变慢
- 在更新参数时,可以在一定程度上保留之前的更新方向
- 参数更新公式:以前的梯度会累积,但是会以α衰减
但是最低点时动量过大,会使得一下子越过最小值,到达其他局部最小值
- 牛顿加速梯度算法(Nesterov Accelerated Gradient, NAG)
(就是先预计下一步的参数,到了下一步再对之前的估计进行修正)
根据当前更新方向,估算下一步的梯度方向(是计算超前梯度,而不是计算当前的梯度,再用超前梯度修正当前的梯度,提高了算法的遇见能力,避免大幅震荡)
在新位置计算梯度,修正上面估计的梯度方向
- Adam:
可以看做是RMSprop+Momentum,而Nadam=Adam+NAG