大纲指数衰减学习率
激活函数
损失函数
缓解过拟合
优化器
1. 指数衰减学习率
思想:先用较大的学习率快速得到近似解,然后逐步减小学习率,使算法在迭代后期稳定下来。计算公式为:
指数衰减学习率=初始学习率*学习率衰减率^(单前轮数/多少轮衰减一次),其中,单前轮数可以指opoch数,也可以指global steps。
例子:
import tensorflow as tf
epoch=40
lr_base=0.2
lr_decay=0.99
lr_step=1
w = tf.Variable(tf.constant(5, dtype=tf.float32))
for epoch in range(epoch):
lr=lr_base*lr_decay**(epoch/lr_step)
with tf.GradientTape() as tape:
loss=tf.square(w+1)
grads=tape.gradient(loss,w)
w.assign_sub(lr*grads)
print("after%spoch, w is%f, loss if%f, lr is%f" %(epoch,w.numpy(),loss,lr))
outputs:
after 0 poch, w is 2.600000, loss if 36.000000, lr is 0.200000
after 1 poch, w is 1.174400, loss if 12.959999, lr is 0.198000
after 2 poch, w is 0.321948, loss if 4.728015, lr is 0.196020
after 3 poch, w is -0.191126, loss if 1.747547, lr is 0.194060
after 4 poch, w is -0.501926, loss if 0.654277, lr is 0.192119
after 5 poch, w is -0.691392, loss if 0.248077, lr is 0.190198
after 6 poch, w is -0.807611, loss if 0.095239, lr is 0.188296
after 7 poch, w is -0.879339, loss if 0.037014, lr is 0.186413
after 8 poch, w is -0.923874, loss if 0.014559, lr is 0.184549
after 9 poch, w is -0.951691, loss if 0.005795, lr is 0.182703
2. 激活函数tf.math.sigmoid(x):数学形式为
,输出范围为[0,1]。特点:(1)大部分梯度接近于0,易造成梯度消失;(2)输出非0均值,收敛慢;(3)幂运算复杂,计算量大。
tf.math.tanh(x):数学形式为
,输出范围为[-1,1]。特点:大部分梯度接近于0,易造成梯度消失;(2)输出0均值;(3)幂运算复杂,计算量大。
tf.nn.relu(x):数学形式为
。优点是:解决了梯度消失问题,运算简单,收录速度远快于sigmoid和tanh。缺点是:输出非0均值,收敛慢;某些神经元的激活值为0,梯度也为0,导致这些神经元的参数永远不会被更新,即Dead relu问题。
tf.nn.leaky_relu(x):数学形式为
。理论上来讲,leaky_relu有relu的所有优点,并且不存在Dead relu问题。
建议:首选relu激活函数
学习率设置为较小的值
输入特征标准化,让输入特征满足0均值,1标注差的正太分布
输出参数中心化,让随机生成的参数满足0均值,
标准差的正太分布,n指当前层输入特征个数。
3. 损失函数
损失函数指预测值y与已知答案y_之间的差距。均方误差
loss_mse=tf.math.reduce_mean(tf.math.square(y_-y))
例子:
import tensorflow as tf
import numpy as np
SEED=23455
rdm=np.random.RandomState(SEED)
x=rdm.rand(32,2)
y_=[[x1+x2+(rdm.rand()/10.-0.05)] for (x1,x2) in x]
x=tf.cast(x,dtype=tf.float32) #tf.cast能对numpy数据进行操作,返回Tensor
#print(x)
w1=tf.Variable(tf.random.normal([2,1],stddev=1,seed=1))
epoch=15000
lr=0.002
for epoch in range(epoch):
with tf.GradientTape() as tape:
y=tf.linalg.matmul(x,w1)
loss_mse=tf.math.reduce_mean(tf.math.square(y-y_)) #Tensor居然能直接减去列表
grads=tape.gradient(loss_mse,w1)
w1.assign_sub(lr*grads)
if epoch%500==0:
print("after%dtraining steps, w1 is" % (epoch))
print(w1.numpy(),"\n")
outputs:
after 14500 training steps, w1 is
[[1.0002553 ]
[0.99838644]]交叉熵
表示两个概率分布之间的距离。交叉熵越大,两个概率分布越远;交叉熵越小,两个概率分布越近。计算公式为:
式中,y_指标准答案,y指网络预测值。
实现方法:tf.losses.categorical_corssentropy(y_,y)
例子:
ce1=tf.losses.categorical_crossentropy([1,0],[0.6,0.4])
ce2=tf.losses.categorical_crossentropy([1,0],[0.8,0.2])
print(ce1)
print(ce2)
outputs:
tf.Tensor(0.5108256, shape=(), dtype=float32)
tf.Tensor(0.22314353, shape=(), dtype=float32)softmax和交叉熵结合
tf.nn.softmax_cross_entropy_with_logits(y_, y)
下面例子说明了softmax_cross_entropy_with_logits等价于softmax和categorical_crossentropy:
y_=np.array([[1,0,0],
[0,1,0],
[0,0,1],
[1,0,0]])
y=np.array([[12,3,2],
[3,10,1],
[1,2,5],
[4,6.5,1]])
y_pred=tf.nn.softmax(y)
loss1=tf.losses.categorical_crossentropy(y_,y_pred)
loss2=tf.nn.softmax_cross_entropy_with_logits(y_,y)
print(loss1)
print(loss2)
outputs:
tf.Tensor([1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58265938e+00], shape=(4,), dtype=float64)
tf.Tensor([1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58265938e+00], shape=(4,), dtype=float64)自定义
mse和交叉熵不一定是最优的loss,有时候可自定义loss。
4. 缓解过拟合正则化
正则化在损失函数中引入模型复杂度指标,利用给w加权值,弱化了训练数据的噪声(一般不正则化b)。数学形式为:
权值w的正则化一般有L1和L2正则化:
正则化的选择:
(1)L1正则化大概率会使很多参数变为0,因此它通过稀疏参数减少参数的数量,降低复杂度。
(2)L2正则化会使很多参数接近于0但不为0,因此它通过减小参数大小降低复杂度。
例子:
import tensorflow as tf
import numpy as np
from matplotlib import pyplot as plt
import pandas as pd
# 读入数据和标签
df=pd.read_csv('dot.csv')
x_data=np.array(df[['x1','x2']]) #shape (300,2)
y_data=np.array(df['y_c']) #shape (300,)
y_data=y_data.reshape(-1,1) #shape (300,1)
Y_c=[['red' if y else 'blue'] for y in y_data]
# 转换数据类型,否则后面矩阵相乘时会因数据类型问题报错
x_train=tf.cast(x_data,tf.float32) #tf函数能直接处理numpy数据,很有趣
y_train=tf.cast(y_data,tf.float32)
# 配对数据,切分数据
train_db=tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)
# 生成神经网络的参数,并保证参数可训练
w1=tf.Variable(tf.random.normal([2,11]),dtype=tf.float32)
b1=tf.Variable(tf.constant(0.01,shape=[11])) #突然间觉得对constant很陌生
w2=tf.Variable(tf.random.normal([11,1]),dtype=tf.float32)
b2=tf.Variable(tf.constant(0.01,shape=[1]))
lr=0.005
epoch=800
# 训练部分
for epoch in range(epoch):
for step,(x_train,y_train) in enumerate(train_db):
with tf.GradientTape() as tape:
h1=tf.linalg.matmul(x_train,w1)+b1
h1=tf.nn.relu(h1)
y=tf.linalg.matmul(h1,w2)+b2
#mse
loss_mse=tf.math.reduce_mean(tf.math.square(y_train-y))
#正则化
loss_regularization=[]
#tf.nn.l2_loss(w1)=sum(w**2)/2,输出一个scalar。使用tf.losses里面很多函数是不求和的,需要注意。
loss_regularization.append(tf.nn.l2_loss(w1))
loss_regularization.append(tf.nn.l2_loss(w2))
loss_regularization=tf.math.reduce_sum(loss_regularization)
loss=loss_mse+0.03*loss_regularization
#求梯度
variables=[w1,b1,w2,b2]
grads=tape.gradient(loss,variables)
# 更新梯度
w1.assign_sub(lr * grads[0])
b1.assign_sub(lr * grads[1])
w2.assign_sub(lr * grads[2])
b2.assign_sub(lr * grads[3])
if epoch%20==0:
print('epoch:',epoch, 'loss:',float(loss))
# 预测部分
print('******************predict*****************')
#xx在-3到3之间以步长为0.1,yy在-3到3之间以步长为0.1,生成间隔数值点
xx,yy=np.mgrid[-3:3:.1,-3:3:.1]
# 将xx和yy拉直,并合并配对为二维张量,生成二维坐标点
grid=np.c_[xx.ravel(),yy.ravel()]
grid=tf.cast(grid,tf.float32)
# 将网格点喂入神经网络进行预测
# probs=[]
# for x_test in grid:
# h1=tf.linalg.matmul([x_test],w1)+b1 #matmul的操作对象是矩阵,所以需要把x_test转换为矩阵
# h1=tf.nn.relu(h1)
# y=tf.linalg.matmul(h1,w2)+b2
# probs.append(y)
h1=tf.linalg.matmul(grid,w1)+b1
h1=tf.nn.relu(h1)
probs=tf.linalg.matmul(h1,w2)+b2
x1=x_data[:,0]
x2=x_data[:,1]
probs=np.array(probs).reshape(xx.shape) #Tensor可直接转换为numpy数据
plt.scatter(x1,x2,color=np.squeeze(Y_c))
plt.contour(xx,yy,probs,levels=[.5])
plt.show()图1 无正则化图2 L2正则化
5. 优化器
神经网络的优化器一般有一下步骤:
Step 1. 计算时刻t损失函数关于当前参数的梯度
Step 2. 计算时刻t的一阶动量
和二阶动量
Step 3. 计算时刻t的下降梯度
Step 4. 计算时刻t+1的参数
不同的优化方法的主要区别在于Step 2。我们来看看5种常见的优化器和它们的实现方法。SGD
SGD的一阶动力和二阶动量分别为
和
例子:
import tensorflow as tf
import numpy as np
from sklearn import datasets
from matplotlib import pyplot as plt
import time
# 读入数据
x_data=datasets.load_iris().data
y_data=datasets.load_iris().target
# 打乱数据
np.random.seed(116) #使用相同的seed,输出相同的随机数
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样
# 划分训练集和测试集
x_train=x_data[:-30]
y_train=y_data[:-30]
x_test=x_data[-30:]
y_test=y_data[-30:]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# 数据集配对
train_db=tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)
test_db=tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(32)
# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1=tf.Variable(tf.random.truncated_normal([4,3],stddev=0.1,seed=1))
b1=tf.Variable(tf.random.truncated_normal([3],stddev=0.1,seed=1))
# 训练神经网络
lr=0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
now_time=time.time()
for epoch in range(epoch):
#训练部分
for step,(x_train,y_train) in enumerate(train_db):
with tf.GradientTape() as tape:
y=tf.linalg.matmul(x_train,w1)+b1
y=tf.nn.softmax(y) # 使输出y符合概率分布
y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads=tape.gradient(loss,[w1,b1])
# 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad
w1.assign_sub(lr*grads[0])
b1.assign_sub(lr*grads[1])
print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
total_correct, total_number = 0, 0
for x_test,y_test in test_db:
# 使用更新后的参数进行预测
y=tf.linalg.matmul(x_test,w1)+b1
y=tf.nn.softmax(y)
pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred=tf.cast(pred,dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)
# 将每个batch的correct数加起来
correct=tf.math.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct+=int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number+=x_test.shape[0]
acc=total_correct/total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time=time.time()-now_time
print('total time',total_time)
# 绘制 loss 曲线
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
plt.show() # 画出图像
# 绘制 Accuracy 曲线
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()SGDM(动量梯度下降法)
SGDM的一阶动量和二阶动量分别为:
和
式中,
是一个接近于1的超参数,一般取0.9。
例子:
import tensorflow as tf
import numpy as np
from sklearn import datasets
from matplotlib import pyplot as plt
import time
# 读入数据
x_data=datasets.load_iris().data
y_data=datasets.load_iris().target
# 打乱数据
np.random.seed(116) #使用相同的seed,输出相同的随机数
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样
# 划分训练集和测试集
x_train=x_data[:-30]
y_train=y_data[:-30]
x_test=x_data[-30:]
y_test=y_data[-30:]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# 数据集配对
train_db=tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)
test_db=tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(32)
# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1=tf.Variable(tf.random.truncated_normal([4,3],stddev=0.1,seed=1))
b1=tf.Variable(tf.random.truncated_normal([3],stddev=0.1,seed=1))
# 训练神经网络
lr=0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
# 动量初值
m_w=tf.constant(0,shape=[4,3],dtype=tf.float32)
m_b=tf.constant(0,shape=[3],dtype=tf.float32)
beta=0.9
now_time=time.time()
for epoch in range(epoch):
#训练部分
for step,(x_train,y_train) in enumerate(train_db):
with tf.GradientTape() as tape:
y=tf.linalg.matmul(x_train,w1)+b1
y=tf.nn.softmax(y) # 使输出y符合概率分布
y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads=tape.gradient(loss,[w1,b1])
# sgd-momentum
m_w=beta*m_w+(1-beta)*grads[0]
m_b=beta*m_b+(1-beta)*grads[1]
w1.assign_sub(lr*grads[0])
b1.assign_sub(lr*grads[1])
print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
total_correct, total_number = 0, 0
for x_test,y_test in test_db:
# 使用更新后的参数进行预测
y=tf.linalg.matmul(x_test,w1)+b1
y=tf.nn.softmax(y)
pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred=tf.cast(pred,dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)
# 将每个batch的correct数加起来
correct=tf.math.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct+=int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number+=x_test.shape[0]
acc=total_correct/total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time=time.time()-now_time
print('total time',total_time)
# 绘制 loss 曲线
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
plt.show() # 画出图像
# 绘制 Accuracy 曲线
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()Adagrad
Adagrad在SGD的基础上分配二阶动量,可以对模型中的每一个参数分配自适应学习率。Adagrad的一阶动量和二阶动量分别为:
和
例子:
import tensorflow as tf
import numpy as np
from sklearn import datasets
from matplotlib import pyplot as plt
import time
# 读入数据
x_data=datasets.load_iris().data
y_data=datasets.load_iris().target
# 打乱数据
np.random.seed(116) #使用相同的seed,输出相同的随机数
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样
# 划分训练集和测试集
x_train=x_data[:-30]
y_train=y_data[:-30]
x_test=x_data[-30:]
y_test=y_data[-30:]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# 数据集配对
train_db=tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)
test_db=tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(32)
# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1=tf.Variable(tf.random.truncated_normal([4,3],stddev=0.1,seed=1))
b1=tf.Variable(tf.random.truncated_normal([3],stddev=0.1,seed=1))
# 训练神经网络
lr=0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
# adagrad
v_w=tf.constant(0,shape=[4,3],dtype=tf.float32)
v_b=tf.constant(0,shape=[3],dtype=tf.float32)
now_time=time.time()
for epoch in range(epoch):
#训练部分
for step,(x_train,y_train) in enumerate(train_db):
with tf.GradientTape() as tape:
y=tf.linalg.matmul(x_train,w1)+b1
y=tf.nn.softmax(y) # 使输出y符合概率分布
y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads=tape.gradient(loss,[w1,b1])
# adagrad
v_w+=tf.math.square(grads[0])
v_b+=tf.math.square(grads[1])
w1.assign_sub(lr*grads[0]/tf.math.sqrt(v_w))
b1.assign_sub(lr*grads[1]/tf.math.sqrt(v_b))
print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
total_correct, total_number = 0, 0
for x_test,y_test in test_db:
# 使用更新后的参数进行预测
y=tf.linalg.matmul(x_test,w1)+b1
y=tf.nn.softmax(y)
pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred=tf.cast(pred,dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)
# 将每个batch的correct数加起来
correct=tf.math.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct+=int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number+=x_test.shape[0]
acc=total_correct/total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time=time.time()-now_time
print('total time',total_time)
# 绘制 loss 曲线
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
plt.show() # 画出图像
# 绘制 Accuracy 曲线
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()RMSProp
它是在SGD基础上增加二阶动量。RMSProp的一阶动量和二阶动量分别为:
和
例子:
import tensorflow as tf
import numpy as np
from sklearn import datasets
from matplotlib import pyplot as plt
import time
# 读入数据
x_data=datasets.load_iris().data
y_data=datasets.load_iris().target
# 打乱数据
np.random.seed(116) #使用相同的seed,输出相同的随机数
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样
# 划分训练集和测试集
x_train=x_data[:-30]
y_train=y_data[:-30]
x_test=x_data[-30:]
y_test=y_data[-30:]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# 数据集配对
train_db=tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)
test_db=tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(32)
# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1=tf.Variable(tf.random.truncated_normal([4,3],stddev=0.1,seed=1))
b1=tf.Variable(tf.random.truncated_normal([3],stddev=0.1,seed=1))
# 训练神经网络
lr=0.001
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
# adagrad
v_w=tf.constant(0,shape=[4,3],dtype=tf.float32)
v_b=tf.constant(0,shape=[3],dtype=tf.float32)
beta=0.9
now_time=time.time()
for epoch in range(epoch):
#训练部分
for step,(x_train,y_train) in enumerate(train_db):
with tf.GradientTape() as tape:
y=tf.linalg.matmul(x_train,w1)+b1
y=tf.nn.softmax(y) # 使输出y符合概率分布
y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads=tape.gradient(loss,[w1,b1])
# rmsprop
v_w=beta*v_w+(1-beta)*tf.math.square(grads[0])
v_b=beta*v_b+(1-beta)*tf.math.square(grads[1])
w1.assign_sub(lr*grads[0]/tf.math.sqrt(v_w))
b1.assign_sub(lr*grads[1]/tf.math.sqrt(v_b))
print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
total_correct, total_number = 0, 0
for x_test,y_test in test_db:
# 使用更新后的参数进行预测
y=tf.linalg.matmul(x_test,w1)+b1
y=tf.nn.softmax(y)
pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred=tf.cast(pred,dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)
# 将每个batch的correct数加起来
correct=tf.math.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct+=int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number+=x_test.shape[0]
acc=total_correct/total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time=time.time()-now_time
print('total time',total_time)
# 绘制 loss 曲线
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
plt.show() # 画出图像
# 绘制 Accuracy 曲线
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()Adam
同时结合了SGDM的一阶动量和RMSProp的二阶动量,即
和
,并在此基础上增加了两个修正项:
例子:
import tensorflow as tf
import numpy as np
from sklearn import datasets
from matplotlib import pyplot as plt
import time
# 读入数据
x_data=datasets.load_iris().data
y_data=datasets.load_iris().target
# 打乱数据
np.random.seed(116) #使用相同的seed,输出相同的随机数
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样
# 划分训练集和测试集
x_train=x_data[:-30]
y_train=y_data[:-30]
x_test=x_data[-30:]
y_test=y_data[-30:]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# 数据集配对
train_db=tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)
test_db=tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(32)
# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1=tf.Variable(tf.random.truncated_normal([4,3],stddev=0.1,seed=1))
b1=tf.Variable(tf.random.truncated_normal([3],stddev=0.1,seed=1))
# 训练神经网络
lr=0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
# adam
m_w=tf.constant(0,shape=[4,3],dtype=tf.float32)
m_b=tf.constant(0,shape=[3],dtype=tf.float32)
v_w=tf.constant(0,shape=[4,3],dtype=tf.float32)
v_b=tf.constant(0,shape=[3],dtype=tf.float32)
beta1=0.9
beta2=0.999
global_step=0
now_time=time.time()
for epoch in range(epoch):
#训练部分
for step,(x_train,y_train) in enumerate(train_db):
global_step+=1
with tf.GradientTape() as tape:
y=tf.linalg.matmul(x_train,w1)+b1
y=tf.nn.softmax(y) # 使输出y符合概率分布
y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads=tape.gradient(loss,[w1,b1])
# adam
m_w = beta1 * m_w + (1-beta1) * grads[0]
m_b = beta1 * m_b + (1 - beta1) * grads[1]
v_w=beta2*v_w+(1-beta2)*tf.math.square(grads[0])
v_b=beta2*v_b+(1-beta2)*tf.math.square(grads[1])
m_w_correction=m_w/(1-tf.pow(beta1,global_step))
m_b_correction=m_b/(1-tf.pow(beta1,global_step))
v_w_correction=v_w/(1-tf.pow(beta2,global_step))
v_b_correction=v_b/(1-tf.pow(beta2,global_step))
w1.assign_sub(lr*m_w_correction/tf.math.sqrt(v_w_correction))
b1.assign_sub(lr*m_b_correction/tf.math.sqrt(v_b_correction))
print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
total_correct, total_number = 0, 0
for x_test,y_test in test_db:
# 使用更新后的参数进行预测
y=tf.linalg.matmul(x_test,w1)+b1
y=tf.nn.softmax(y)
pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred=tf.cast(pred,dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)
# 将每个batch的correct数加起来
correct=tf.math.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct+=int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number+=x_test.shape[0]
acc=total_correct/total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time=time.time()-now_time
print('total time',total_time)
# 绘制 loss 曲线
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
plt.show() # 画出图像
# 绘制 Accuracy 曲线
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()