tf.where
条件语句真返回A,条件语句假返回B
tf.where(条件语句,真返回A,假返回B)
a=tf.constant([1,2,3,1,1])
b=tf.constant([0,1,3,4,5])
c=tf.where(tf.greater(a,b),a,b)
#若a>b,返回a对应位置的元素,否则返回b对应位置的元素
print(c)
#tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)
np.random.RandomState.rand()
返回一个[0,1)之间的随机数
np.random.RandomState.rand(维度)
import numpy as np#seed=常数每次生成随机数相同
rdm=np.random.RandomState(seed=1)
a=rdm.rand()#返回一个随机标量
b=rdm.rand(2,3)#返回维度为2行3列随机数矩阵
print("a:",a)
print("b:",b)
'''
a: 0.417022004702574
b: [[7.20324493e-01 1.14374817e-04 3.02332573e-01]
[1.46755891e-01 9.23385948e-02 1.86260211e-01]]
'''
np.vstack
将两个数组按垂直方向叠加
#np.vstack(数组1,数组2)
a=np.array([1,2,3])
b=np.array([4,5,6])
c=np.vstack((a,b))
print("c:\n",c)
'''
c:
[[1 2 3]
[4 5 6]]
'''
np.mgrid[]
np.mgrid[起始值:结束值:步长,起始值:结束值:步长,…]
x.ravel()
将x变为一维数组,“把 . 前变量拉直”
np.c_[]
使返回的间隔数值点配对
np.c_[数组1,数组2,…]
x,y=np.mgrid[1:3:1,2:4:0.5]
grid=np.c_[x.ravel(),y.ravel()]
print("x:",x)
'''
x: [[1. 1. 1. 1.]
[2. 2. 2. 2.]]
'''
print("y:",y)
'''
y: [[2. 2.5 3. 3.5]
[2. 2.5 3. 3.5]]
'''
print('grid:\n',grid)
'''
grid:
[[1. 2. ]
[1. 2.5]
[1. 3. ]
[1. 3.5]
[2. 2. ]
[2. 2.5]
[2. 3. ]
[2. 3.5]]
'''
空间复杂度:
时间复杂度:
学习率
w t + 1 = w t − l r ∗ α l o s s α w t w_{t+1}=w_t-lr*\frac{αloss}{αw_t} wt+1=wt−lr∗αwtαloss
更新后的参数 = 当前参数 − 学习率 ∗ 损失函数的梯度 更新后的参数=当前参数-学习率*损失函数的梯度 更新后的参数=当前参数−学习率∗损失函数的梯度
e g : 损失函数 l o s s = ( w + 1 ) 2 eg:损失函数loss=(w+1)^2 eg:损失函数loss=(w+1)2
α l o s s α w = 2 w + 2 \frac{αloss}{αw}=2w+2 αwαloss=2w+2
指数衰减学习率
可以先用较大的学习率,快速得到较优解,然后逐步减小学习率,是模型在训练后期稳定。
指数衰减学习率 = 初始学习率 ∗ 学习衰减 率 ( 当前轮数 / 多少轮衰减一次 ) 指数衰减学习率=初始学习率*学习衰减率^{(当前轮数/多少轮衰减一次)} 指数衰减学习率=初始学习率∗学习衰减率(当前轮数/多少轮衰减一次)
import tensorflow as tf
w = tf.Variable(tf.constant(5, dtype=tf.float32))
epoch = 40
LR_BASE = 0.2 # 最初学习率
LR_DECAY = 0.99 # 学习率衰减率
LR_STEP = 1 # 喂入多少轮BATCH_SIZE后,更新一次学习率
for epoch in range(epoch): # for epoch 定义顶层循环,表示对数据集循环epoch次,此例数据集数据仅有1个w,初始化时候constant赋值为5,循环100次迭代。
lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)
with tf.GradientTape() as tape: # with结构到grads框起了梯度的计算过程。
loss = tf.square(w + 1)
grads = tape.gradient(loss, w) # .gradient函数告知谁对谁求导
w.assign_sub(lr * grads) # .assign_sub 对变量做自减 即:w -= lr*grads 即 w = w - lr*grads
print("After %s epoch,w is %f,loss is %f,lr is %f" % (epoch, w.numpy(), loss, lr))
After 0 epoch,w is 2.600000,loss is 36.000000,lr is 0.200000
After 1 epoch,w is 1.174400,loss is 12.959999,lr is 0.198000
After 2 epoch,w is 0.321948,loss is 4.728015,lr is 0.196020
After 3 epoch,w is -0.191126,loss is 1.747547,lr is 0.194060
After 4 epoch,w is -0.501926,loss is 0.654277,lr is 0.192119
After 5 epoch,w is -0.691392,loss is 0.248077,lr is 0.190198
After 6 epoch,w is -0.807611,loss is 0.095239,lr is 0.188296
After 7 epoch,w is -0.879339,loss is 0.037014,lr is 0.186413
After 8 epoch,w is -0.923874,loss is 0.014559,lr is 0.184549
After 9 epoch,w is -0.951691,loss is 0.005795,lr is 0.182703
After 10 epoch,w is -0.969167,loss is 0.002334,lr is 0.180876
After 11 epoch,w is -0.980209,loss is 0.000951,lr is 0.179068
After 12 epoch,w is -0.987226,loss is 0.000392,lr is 0.177277
After 13 epoch,w is -0.991710,loss is 0.000163,lr is 0.175504
After 14 epoch,w is -0.994591,loss is 0.000069,lr is 0.173749
After 15 epoch,w is -0.996452,loss is 0.000029,lr is 0.172012
After 16 epoch,w is -0.997660,loss is 0.000013,lr is 0.170292
After 17 epoch,w is -0.998449,loss is 0.000005,lr is 0.168589
After 18 epoch,w is -0.998967,loss is 0.000002,lr is 0.166903
After 19 epoch,w is -0.999308,loss is 0.000001,lr is 0.165234
After 20 epoch,w is -0.999535,loss is 0.000000,lr is 0.163581
After 21 epoch,w is -0.999685,loss is 0.000000,lr is 0.161946
After 22 epoch,w is -0.999786,loss is 0.000000,lr is 0.160326
After 23 epoch,w is -0.999854,loss is 0.000000,lr is 0.158723
After 24 epoch,w is -0.999900,loss is 0.000000,lr is 0.157136
After 25 epoch,w is -0.999931,loss is 0.000000,lr is 0.155564
After 26 epoch,w is -0.999952,loss is 0.000000,lr is 0.154009
After 27 epoch,w is -0.999967,loss is 0.000000,lr is 0.152469
After 28 epoch,w is -0.999977,loss is 0.000000,lr is 0.150944
After 29 epoch,w is -0.999984,loss is 0.000000,lr is 0.149434
After 30 epoch,w is -0.999989,loss is 0.000000,lr is 0.147940
After 31 epoch,w is -0.999992,loss is 0.000000,lr is 0.146461
After 32 epoch,w is -0.999994,loss is 0.000000,lr is 0.144996
After 33 epoch,w is -0.999996,loss is 0.000000,lr is 0.143546
After 34 epoch,w is -0.999997,loss is 0.000000,lr is 0.142111
After 35 epoch,w is -0.999998,loss is 0.000000,lr is 0.140690
After 36 epoch,w is -0.999999,loss is 0.000000,lr is 0.139283
After 37 epoch,w is -0.999999,loss is 0.000000,lr is 0.137890
After 38 epoch,w is -0.999999,loss is 0.000000,lr is 0.136511
After 39 epoch,w is -0.999999,loss is 0.000000,lr is 0.135146
Sigmoid函数
tf.nn.sigmoid(x)
f ( x ) = 1 1 + e − x f(x)=\frac{1}{1+e^{-x}} f(x)=1+e−x1
sigmod激活函数把输入值变换到0和1之间输出,如果输入值是非常大的负数,输出的就是0,如果输入值是非常大的整数,输出的就是1,相当于对输入进行了归一化。
深层神经网络更新参数时,需要从输出层到输入层逐层进行链式求导,而sigmoid函数的导数输出是0到0.25之间的小数,链式求导需要多层导数连续相乘,会出现多个0到0.25之间的小数连续相乘,结果将趋于0,产生梯度消失。使得参数无法继续更新。
我们希望输入每层神经网络的特征是以0为均值的小数值,但是过sigmoid函数的数据都是整数,会使收敛变慢。
另外sigmod函数存在幂运算,会使训练时间过长。
特点:
Tanh函数
tf.math.tanh(x)
f ( x ) = 1 − e − 2 x 1 + e − 2 x f(x)=\frac{1-e^{-2x}}{1+e^{-2x}} f(x)=1+e−2x1−e−2x
从函数图像看,这个函数的输出值为0均值,但是依旧存在梯度消失和幂运算问题。
Relu函数
tf.nn.relu(x)
f ( x ) = m a x ( x , 0 ) { 0 x<0 1 x>=0 f(x)= max(x,0)\begin{cases} 0& \text{x<0} \\ 1 & \text{x>=0} \end{cases} f(x)=max(x,0){01x<0x>=0
优点
缺点
Leaky Relu函数
tf.nn.Leaky_relu(x)
f ( x ) = m a x ( α x , x ) f(x)=max(αx,x) f(x)=max(αx,x)
此函数是为解决relu负区间为0引起神经元死亡问题而设计,leaky relu负区间引入了一个固定的斜率α,使得relu负区间不再恒等于0,
理论上讲,Leaky Relu有Relu的所有优点,外加不会有Dead Relu问题,但是在实际操作中,并没有完全证明Leaky Relu总是好于Relu。
对于激活函数的建议
首选relu激活函数
学习率设置较小值
输入特征标准化,即让随机生成的参数满足以0为均值,
2 当前层输入特征个数 为标准差的正太分布。 \sqrt{\frac{2}{当前层输入特征个数}}为标准差的正太分布。 当前层输入特征个数2为标准差的正太分布。
预测值(y)与已知答案(y_)的差距。
神经网络的优化目标就是找到某套参数使得计算出来的结果y与已知标准答案y_无限接近。也就是他们的差距loss值无限小。
主流loss有三种计算方法:
N N 优化目标: l o s s 最小 → { 均方误差 m s e ( M e a n S q u a r d E r r o r ) 自定义 交叉熵 c e ( C r o s s E n t r o p y ) NN优化目标:loss最小→ \begin{cases} 均方误差mse(Mean Squard Error) \\自定义 \\ 交叉熵ce(Cross Entropy)\end{cases} NN优化目标:loss最小→⎩ ⎨ ⎧均方误差mse(MeanSquardError)自定义交叉熵ce(CrossEntropy)
均方误差
m s e : M S E ( y − , y ) = ∑ i = 1 n ( y − y − ) 2 n mse:MSE(y_-,y)=\frac{\sum^{n}_{i=1}(y-y_-)^2}{n} mse:MSE(y−,y)=n∑i=1n(y−y−)2
loss_mse=tf.reduce_mean(tf.square(y_-y))
预测酸奶日销量y,x1、x2是影响日销量的因素。
建模前,一个预先采集的数据有:每日x1、x2和销量y_(即已知答案,最佳情况:产量=销量),拟造数据集X,Y;y_=x1,x2 噪声:-0.02~+0.05 拟合预测销售量。
import tensorflow as tf
import numpy as np
SEED = 23455
rdm = np.random.RandomState(seed=SEED) # 生成[0,1)之间的随机数
x = rdm.rand(32, 2)
y_ = [[x1 + x2 + (rdm.rand() / 10.0 - 0.05)] for (x1, x2) in x] # 生成噪声[0,1)/10=[0,0.1); [0,0.1)-0.05=[-0.05,0.05)
x = tf.cast(x, dtype=tf.float32)
w1 = tf.Variable(tf.random.normal([2, 1], stddev=1, seed=1))#随机初始化参数w1,为两行一列
epoch = 15000
lr = 0.002
for epoch in range(epoch):
with tf.GradientTape() as tape:
y = tf.matmul(x, w1)
loss_mse = tf.reduce_mean(tf.square(y_ - y))
grads = tape.gradient(loss_mse, w1)#偏导
w1.assign_sub(lr * grads)
if epoch % 500 == 0:
print("%d次训练之后,参数w1是:" % (epoch))
print(w1.numpy(), "\n")
print("最后的参数w1是: ", w1.numpy())
0次训练之后,参数w1是:
[[-0.8096241]
[ 1.4855157]]
500次训练之后,参数w1是:
[[-0.21934733]
[ 1.6984866 ]]
1000次训练之后,参数w1是:
[[0.0893971]
[1.673225 ]]
1500次训练之后,参数w1是:
[[0.28368822]
[1.5853055 ]]
2000次训练之后,参数w1是:
[[0.423243 ]
[1.4906037]]
2500次训练之后,参数w1是:
[[0.531055 ]
[1.4053345]]
3000次训练之后,参数w1是:
[[0.61725086]
[1.332841 ]]
3500次训练之后,参数w1是:
[[0.687201 ]
[1.2725208]]
4000次训练之后,参数w1是:
[[0.7443262]
[1.2227542]]
4500次训练之后,参数w1是:
[[0.7910986]
[1.1818361]]
5000次训练之后,参数w1是:
[[0.82943517]
[1.1482395 ]]
5500次训练之后,参数w1是:
[[0.860872 ]
[1.1206709]]
6000次训练之后,参数w1是:
[[0.88665503]
[1.098054 ]]
6500次训练之后,参数w1是:
[[0.90780276]
[1.0795006 ]]
7000次训练之后,参数w1是:
[[0.92514884]
[1.0642821 ]]
7500次训练之后,参数w1是:
[[0.93937725]
[1.0517985 ]]
8000次训练之后,参数w1是:
[[0.951048]
[1.041559]]
8500次训练之后,参数w1是:
[[0.96062106]
[1.0331597 ]]
9000次训练之后,参数w1是:
[[0.9684733]
[1.0262702]]
9500次训练之后,参数w1是:
[[0.97491425]
[1.0206193 ]]
10000次训练之后,参数w1是:
[[0.9801975]
[1.0159837]]
10500次训练之后,参数w1是:
[[0.9845312]
[1.0121814]]
11000次训练之后,参数w1是:
[[0.9880858]
[1.0090628]]
11500次训练之后,参数w1是:
[[0.99100184]
[1.0065047 ]]
12000次训练之后,参数w1是:
[[0.9933934]
[1.0044063]]
12500次训练之后,参数w1是:
[[0.9953551]
[1.0026854]]
13000次训练之后,参数w1是:
[[0.99696386]
[1.0012728 ]]
13500次训练之后,参数w1是:
[[0.9982835]
[1.0001147]]
14000次训练之后,参数w1是:
[[0.9993659]
[0.999166 ]]
14500次训练之后,参数w1是:
[[1.0002553 ]
[0.99838644]]
最后的参数w1是: [[1.0009792]
[0.9977485]]
欠拟合的解决方法:
过拟合的解决方法:
正则化在损失函数中引入模型复杂度指标,利用给w加权值,弱化了训练数据的噪声(一般正则化b)
l o s s L 1 ( w ) = ∑ i ∣ w i ∣ loss_{L1}(w)=\sum_i|w_i| lossL1(w)=i∑∣wi∣
l o s s L 2 = ∑ i ∣ w i 2 ∣ loss_{L2}=\sum_i|{w_i}^2| lossL2=i∑∣wi2∣
正则化的选择:
L1正则化大概率会使很多参数变为0,因此该方法可通过稀疏参数,即减小参数的数量,降低复杂度。
L2正则化会使参数很接近0但不为0,因此该方法可以通过减小参数值的大小降低复杂度。
#不用正则化缓解过拟合
# 导入所需模块
import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
# 读入数据/标签 生成x_train y_train
df = pd.read_csv('dot.csv')
x_data = np.array(df[['x1', 'x2']])
y_data = np.array(df['y_c'])
x_train = np.vstack(x_data).reshape(-1, 2)
y_train = np.vstack(y_data).reshape(-1, 1)
Y_c = [['red' if y else 'blue'] for y in y_train]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型问题报错
x_train = tf.cast(x_train, tf.float32)
y_train = tf.cast(y_train, tf.float32)
# from_tensor_slices函数切分传入的张量的第一个维度,生成相应的数据集,使输入特征和标签值一一对应
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
# 生成神经网络的参数,输入层为2个神经元,隐藏层为11个神经元,1层隐藏层,输出层为1个神经元
# 用tf.Variable()保证参数可训练
w1 = tf.Variable(tf.random.normal([2, 11]), dtype=tf.float32)
b1 = tf.Variable(tf.constant(0.01, shape=[11]))
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.matmul(x_train, w1) + b1 # 记录神经网络乘加运算
h1 = tf.nn.relu(h1)
y = tf.matmul(h1, w2) + b2
# 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss = tf.reduce_mean(tf.square(y_train - y))
# 计算loss对各个参数的梯度
variables = [w1, b1, w2, b2]
grads = tape.gradient(loss, variables)
# 实现梯度更新
# w1 = w1 - lr * w1_grad tape.gradient是自动求导结果与[w1, b1, w2, b2] 索引为0,1,2,3
w1.assign_sub(lr * grads[0])
b1.assign_sub(lr * grads[1])
w2.assign_sub(lr * grads[2])
b2.assign_sub(lr * grads[3])
# 每20个epoch,打印loss信息
if epoch % 20 == 0:
print('epoch:', epoch, 'loss:', float(loss))
# 预测部分
print("*******predict*******")
# xx在-3到3之间以步长为0.01,yy在-3到3之间以步长0.01,生成间隔数值点
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为输出
probs = []
for x_test in grid:
# 使用训练好的参数进行预测
h1 = tf.matmul([x_test], w1) + b1
h1 = tf.nn.relu(h1)
y = tf.matmul(h1, w2) + b2 # y为预测结果
probs.append(y)
# 取第0列给x1,取第1列给x2
x1 = x_data[:, 0]
x2 = x_data[:, 1]
# probs的shape调整成xx的样子
probs = np.array(probs).reshape(xx.shape)
plt.scatter(x1, x2, color=np.squeeze(Y_c)) # squeeze去掉纬度是1的纬度,相当于去掉[['red'],[''blue]],内层括号变为['red','blue']
# 把坐标xx yy和对应的值probs放入contour函数,给probs值为0.5的所有点上色 plt.show()后 显示的是红蓝点的分界线
plt.contour(xx, yy, probs, levels=[.5])
plt.show()
epoch: 0 loss: 2.6885414123535156
epoch: 20 loss: 0.22224044799804688
epoch: 40 loss: 0.1120782420039177
epoch: 60 loss: 0.09619641304016113
epoch: 80 loss: 0.08289148658514023
epoch: 100 loss: 0.0699525848031044
epoch: 120 loss: 0.05928531289100647
epoch: 140 loss: 0.05095839500427246
epoch: 160 loss: 0.045101866126060486
epoch: 180 loss: 0.04116815701127052
epoch: 200 loss: 0.03841979801654816
epoch: 220 loss: 0.03676127642393112
epoch: 240 loss: 0.035571467131376266
epoch: 260 loss: 0.03456077724695206
epoch: 280 loss: 0.03379254415631294
epoch: 300 loss: 0.033133622258901596
epoch: 320 loss: 0.03213334083557129
epoch: 340 loss: 0.03136168047785759
epoch: 360 loss: 0.03075394034385681
epoch: 380 loss: 0.030162369832396507
epoch: 400 loss: 0.0296154897660017
epoch: 420 loss: 0.029028693214058876
epoch: 440 loss: 0.02868691273033619
epoch: 460 loss: 0.028423717245459557
epoch: 480 loss: 0.027914607897400856
epoch: 500 loss: 0.027126014232635498
epoch: 520 loss: 0.026477687060832977
epoch: 540 loss: 0.02619301714003086
epoch: 560 loss: 0.025801293551921844
epoch: 580 loss: 0.025305872783064842
epoch: 600 loss: 0.02490360476076603
epoch: 620 loss: 0.0245352853089571
epoch: 640 loss: 0.02424515224993229
epoch: 660 loss: 0.024027755483984947
epoch: 680 loss: 0.023753395304083824
epoch: 700 loss: 0.023446641862392426
epoch: 720 loss: 0.023198598995804787
epoch: 740 loss: 0.023000406101346016
epoch: 760 loss: 0.022870689630508423
epoch: 780 loss: 0.02276296727359295
*******predict*******
#添加L2正则化缓解过拟合
# 导入所需模块
import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
# 读入数据/标签 生成x_train y_train
df = pd.read_csv('dot.csv')
x_data = np.array(df[['x1', 'x2']])
y_data = np.array(df['y_c'])
x_train = x_data
y_train = y_data.reshape(-1, 1)
Y_c = [['red' if y else 'blue'] for y in y_train]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型问题报错
x_train = tf.cast(x_train, tf.float32)
y_train = tf.cast(y_train, tf.float32)
# from_tensor_slices函数切分传入的张量的第一个维度,生成相应的数据集,使输入特征和标签值一一对应
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
# 生成神经网络的参数,输入层为4个神经元,隐藏层为32个神经元,2层隐藏层,输出层为3个神经元
# 用tf.Variable()保证参数可训练
w1 = tf.Variable(tf.random.normal([2, 11]), dtype=tf.float32)
b1 = tf.Variable(tf.constant(0.01, shape=[11]))
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.matmul(x_train, w1) + b1 # 记录神经网络乘加运算
h1 = tf.nn.relu(h1)
y = tf.matmul(h1, w2) + b2
# 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_mse = tf.reduce_mean(tf.square(y_train - y))
# 添加l2正则化
loss_regularization = []
# tf.nn.l2_loss(w)=sum(w ** 2) / 2
loss_regularization.append(tf.nn.l2_loss(w1))
loss_regularization.append(tf.nn.l2_loss(w2))
# 求和
# 例:x=tf.constant(([1,1,1],[1,1,1]))
# tf.reduce_sum(x)
# >>>6
loss_regularization = tf.reduce_sum(loss_regularization)
loss = loss_mse + 0.03 * loss_regularization # REGULARIZER = 0.03
# 计算loss对各个参数的梯度
variables = [w1, b1, w2, b2]
grads = tape.gradient(loss, variables)
# 实现梯度更新
# w1 = w1 - lr * w1_grad
w1.assign_sub(lr * grads[0])
b1.assign_sub(lr * grads[1])
w2.assign_sub(lr * grads[2])
b2.assign_sub(lr * grads[3])
# 每200个epoch,打印loss信息
if epoch % 20 == 0:
print('epoch:', epoch, 'loss:', float(loss))
# 预测部分
print("*******predict*******")
# xx在-3到3之间以步长为0.01,yy在-3到3之间以步长0.01,生成间隔数值点
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为输出
probs = []
for x_predict in grid:
# 使用训练好的参数进行预测
h1 = tf.matmul([x_predict], w1) + b1
h1 = tf.nn.relu(h1)
y = tf.matmul(h1, w2) + b2 # y为预测结果
probs.append(y)
# 取第0列给x1,取第1列给x2
x1 = x_data[:, 0]
x2 = x_data[:, 1]
# probs的shape调整成xx的样子
probs = np.array(probs).reshape(xx.shape)
plt.scatter(x1, x2, color=np.squeeze(Y_c))
# 把坐标xx yy和对应的值probs放入contour函数,给probs值为0.5的所有点上色 plt.show()后 显示的是红蓝点的分界线
plt.contour(xx, yy, probs, levels=[.5])
plt.show()
epoch: 0 loss: 3.4265811443328857
epoch: 20 loss: 0.37931960821151733
epoch: 40 loss: 0.338462233543396
epoch: 60 loss: 0.31492820382118225
epoch: 80 loss: 0.2973583936691284
epoch: 100 loss: 0.28228306770324707
epoch: 120 loss: 0.2681678831577301
epoch: 140 loss: 0.2549345791339874
epoch: 160 loss: 0.2427280843257904
epoch: 180 loss: 0.2312375009059906
epoch: 200 loss: 0.22051842510700226
epoch: 220 loss: 0.2104397416114807
epoch: 240 loss: 0.20090797543525696
epoch: 260 loss: 0.1919662058353424
epoch: 280 loss: 0.1836123913526535
epoch: 300 loss: 0.1756930947303772
epoch: 320 loss: 0.16794028878211975
epoch: 340 loss: 0.16077259182929993
epoch: 360 loss: 0.15424782037734985
epoch: 380 loss: 0.14818936586380005
epoch: 400 loss: 0.1425633281469345
epoch: 420 loss: 0.1373162418603897
epoch: 440 loss: 0.13237838447093964
epoch: 460 loss: 0.1277611255645752
epoch: 480 loss: 0.12343335151672363
epoch: 500 loss: 0.11944165825843811
epoch: 520 loss: 0.11573526263237
epoch: 540 loss: 0.11226116120815277
epoch: 560 loss: 0.10905513912439346
epoch: 580 loss: 0.1060510203242302
epoch: 600 loss: 0.10322703421115875
epoch: 620 loss: 0.10060511529445648
epoch: 640 loss: 0.09817344695329666
epoch: 660 loss: 0.09592539817094803
epoch: 680 loss: 0.09385444223880768
epoch: 700 loss: 0.09194330126047134
epoch: 720 loss: 0.09018189460039139
epoch: 740 loss: 0.08855944871902466
epoch: 760 loss: 0.08707273006439209
epoch: 780 loss: 0.08571130037307739
*******predict*******
神经网络是基于连接的人工智能,当网络结构固定后,不同参数选取对模型的表达力影响很大,更新模型参数的过程仿佛是在教一个孩子理解世界。
达到学龄的孩子,脑神经元的结构、规模是相似的,他们都具备了学习的潜力,但是不同的引导方法,会让孩子具备不同的能力,达到不同的高度。
待优化参数w,损失函数loss,学习率lr,每次迭代一个batch,t表示当前batch迭代的总次数。
1. 计算 t 时刻损失函数关于当前参数的梯度 g t = V ˉ l o s s = α l o s s α ( w t ) 1.计算t时刻损失函数关于当前参数的梯度g_t=\bar{V}loss=\frac{αloss}{α(w_t)} 1.计算t时刻损失函数关于当前参数的梯度gt=Vˉloss=α(wt)αloss
2. 计算 t 时刻一阶动量 m t 和二阶动量 V t 2.计算t时刻一阶动量m_t和二阶动量V_t 2.计算t时刻一阶动量mt和二阶动量Vt
3. 计算 t 时刻下降梯度: η t = l r ∗ m t V t 3.计算t时刻下降梯度:η_t=lr*\frac{m_t}{\sqrt{V_t}} 3.计算t时刻下降梯度:ηt=lr∗Vtmt
4. 计算 t + 1 时刻参数: w t + 1 = w t − η t = w t − l r ∗ m t V t 4.计算t+1时刻参数:w_{t+1}=w_t-η_t=w_t-lr*\frac{m_t}{\sqrt{V_t}} 4.计算t+1时刻参数:wt+1=wt−ηt=wt−lr∗Vtmt
一阶动量:与梯度相关的函数
二阶动量:与梯度平方相关的函数
优化器,常用梯度下降法。
一阶动量定义为梯度: m t = g t 一阶动量定义为梯度:m_t=g_t 一阶动量定义为梯度:mt=gt
二阶动量恒等于 1 : V t = 1 二阶动量恒等于1:V_t=1 二阶动量恒等于1:Vt=1
η t = l r ∗ m t V t = l r ∗ g t η_t=lr*\frac{m_t}{V_t}=lr*g_t ηt=lr∗Vtmt=lr∗gt
下一时刻的参数等于: w t + 1 = w t − η t = w t − l r ∗ m t V t = w t − l r ∗ g t 下一时刻的参数等于:w_{t+1}=w_t-η_t=w_t-lr*\frac{m_t}{\sqrt{V_t}}=w_t-lr*g_t 下一时刻的参数等于:wt+1=wt−ηt=wt−lr∗Vtmt=wt−lr∗gt
# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
# 导入所需模块
import tensorflow as tf
import numpy as np
from sklearn import datasets
from matplotlib import pyplot as plt
import time ##1##
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
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)
# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
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 # 学习率为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() ##2##
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.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]) # 参数w1自更新
b1.assign_sub(lr * grads[1]) # 参数b自更新
# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all / 4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time = time.time() - now_time ##3##
print("total_time", total_time) ##4##
# 绘制 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()
.
.
.
Epoch 484, loss: 0.03271409869194031
Test_acc: 1.0
--------------------------
Epoch 485, loss: 0.03268669778481126
Test_acc: 1.0
--------------------------
Epoch 486, loss: 0.03265940165147185
Test_acc: 1.0
--------------------------
Epoch 487, loss: 0.03263220191001892
Test_acc: 1.0
--------------------------
Epoch 488, loss: 0.032605105079710484
Test_acc: 1.0
--------------------------
Epoch 489, loss: 0.032578098587691784
Test_acc: 1.0
--------------------------
Epoch 490, loss: 0.03255118941888213
Test_acc: 1.0
--------------------------
Epoch 491, loss: 0.032524386420845985
Test_acc: 1.0
--------------------------
Epoch 492, loss: 0.032497681211680174
Test_acc: 1.0
--------------------------
Epoch 493, loss: 0.03247106494382024
Test_acc: 1.0
--------------------------
Epoch 494, loss: 0.03244455344974995
Test_acc: 1.0
--------------------------
Epoch 495, loss: 0.032418133690953255
Test_acc: 1.0
--------------------------
Epoch 496, loss: 0.03239180473610759
Test_acc: 1.0
--------------------------
Epoch 497, loss: 0.03236558195203543
Test_acc: 1.0
--------------------------
Epoch 498, loss: 0.032339440658688545
Test_acc: 1.0
--------------------------
Epoch 499, loss: 0.032313397619873285
Test_acc: 1.0
--------------------------
total_time 8.920095205307007
SGDM(含momentum的SGD),在SGD基础上增加上一时刻的一阶动量。
各时刻梯度方向的指数滑动平均值: m t = β ∗ m t − 1 + ( 1 − β ) ∗ g t 各时刻梯度方向的指数滑动平均值:m_t=β*m_{t-1}+(1-β)*g_t 各时刻梯度方向的指数滑动平均值:mt=β∗mt−1+(1−β)∗gt
β是超参数,是个接近1的数值。
二阶动量在 S G D M 中仍是恒等于 1 : V t = 1 二阶动量在SGDM中仍是恒等于1:V_t=1 二阶动量在SGDM中仍是恒等于1:Vt=1
把一阶动量和二阶动量带入η计算公式
η t = l r ∗ m t V t = l r ∗ m t = l r ∗ ( β ∗ m t − 1 + ( 1 + β ) ∗ g t ) η_t=lr*\frac{m_t}{\sqrt{V_t}}=lr*m_t=lr*(β*m_{t-1}+(1+β)*g_t) ηt=lr∗Vtmt=lr∗mt=lr∗(β∗mt−1+(1+β)∗gt)
再把η带入参数更新公式
w t + 1 = w t − η t = w t − l r ∗ ( β ∗ m t − 1 + ( 1 + β ) ∗ g t ) w_{t+1}=w_t-η_t=w_t-lr*(β*m_{t-1}+(1+β)*g_t) wt+1=wt−ηt=wt−lr∗(β∗mt−1+(1+β)∗gt)
# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
# 导入所需模块
import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np
import time ##1##
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
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)
# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
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 # 学习率为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, m_b = 0, 0
beta = 0.9
##########################################################################
# 训练部分
now_time = time.time() ##2##
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.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-momentun
m_w = beta * m_w + (1 - beta) * grads[0]
m_b = beta * m_b + (1 - beta) * grads[1]
w1.assign_sub(lr * m_w)
b1.assign_sub(lr * m_b)
##########################################################################
# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all / 4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time = time.time() - now_time ##3##
print("total_time", total_time) ##4##
# 绘制 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()
.
.
.
Epoch 488, loss: 0.03092705924063921
Test_acc: 1.0
--------------------------
Epoch 489, loss: 0.03090124297887087
Test_acc: 1.0
--------------------------
Epoch 490, loss: 0.030875515658408403
Test_acc: 1.0
--------------------------
Epoch 491, loss: 0.03084988985210657
Test_acc: 1.0
--------------------------
Epoch 492, loss: 0.030824352987110615
Test_acc: 1.0
--------------------------
Epoch 493, loss: 0.030798905063420534
Test_acc: 1.0
--------------------------
Epoch 494, loss: 0.030773557722568512
Test_acc: 1.0
--------------------------
Epoch 495, loss: 0.030748290475457907
Test_acc: 1.0
--------------------------
Epoch 496, loss: 0.030723126139491796
Test_acc: 1.0
--------------------------
Epoch 497, loss: 0.030698041897267103
Test_acc: 1.0
--------------------------
Epoch 498, loss: 0.030673045199364424
Test_acc: 1.0
--------------------------
Epoch 499, loss: 0.030648143962025642
Test_acc: 1.0
--------------------------
total_time 7.808829069137573
在SGD基础上增加二阶动量。
一阶动量跟 S G D 一样,是等于自己的梯度: m t = g t 一阶动量跟SGD一样,是等于自己的梯度:m_t=g_t 一阶动量跟SGD一样,是等于自己的梯度:mt=gt
二阶动量是从开始到现在,梯度平方的累加和: V t = ∑ t = 1 t g t 2 二阶动量是从开始到现在,梯度平方的累加和:V_t=\sum^t_{t=1}g^2_t 二阶动量是从开始到现在,梯度平方的累加和:Vt=t=1∑tgt2
一阶动量和二阶动量带入η计算公式
η t = l r ∗ m t V t = l r ∗ g t ∑ t = 1 t g t 2 η_t=lr*\frac{m_t}{\sqrt{V_t}}=lr*\frac{g_t}{\sqrt{{\sum^t_{t=1}}g^2_t}} ηt=lr∗Vtmt=lr∗∑t=1tgt2gt
参数更新公式: w t + 1 = w t − η t = w t − l r ∗ m t V t = l r ∗ g t ∑ t = 1 t g t 2 参数更新公式:w_{t+1}=w_t-η_t=w_t-lr*\frac{m_t}{\sqrt{V_t}}=lr*\frac{g_t}{\sqrt{{\sum^t_{t=1}}g^2_t}} 参数更新公式:wt+1=wt−ηt=wt−lr∗Vtmt=lr∗∑t=1tgt2gt
# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
# 导入所需模块
import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np
import time ##1##
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
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)
# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
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 # 学习率为0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
##########################################################################
v_w, v_b = 0, 0
##########################################################################
# 训练部分
now_time = time.time() ##2##
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.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.square(grads[0])
v_b += tf.square(grads[1])
w1.assign_sub(lr * grads[0] / tf.sqrt(v_w))
b1.assign_sub(lr * grads[1] / tf.sqrt(v_b))
##########################################################################
# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all / 4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time = time.time() - now_time ##3##
print("total_time", total_time) ##4##
# 绘制 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()
.
.
.
Epoch 488, loss: 0.03197252610698342
Test_acc: 1.0
--------------------------
Epoch 489, loss: 0.03195097669959068
Test_acc: 1.0
--------------------------
Epoch 490, loss: 0.03192949667572975
Test_acc: 1.0
--------------------------
Epoch 491, loss: 0.03190809162333608
Test_acc: 1.0
--------------------------
Epoch 492, loss: 0.03188674710690975
Test_acc: 1.0
--------------------------
Epoch 493, loss: 0.031865477561950684
Test_acc: 1.0
--------------------------
Epoch 494, loss: 0.03184427414089441
Test_acc: 1.0
--------------------------
Epoch 495, loss: 0.03182313917204738
Test_acc: 1.0
--------------------------
Epoch 496, loss: 0.03180206706747413
Test_acc: 1.0
--------------------------
Epoch 497, loss: 0.03178106527775526
Test_acc: 1.0
--------------------------
Epoch 498, loss: 0.031760127283632755
Test_acc: 1.0
--------------------------
Epoch 499, loss: 0.03173925681039691
Test_acc: 1.0
--------------------------
total_time 9.275285243988037
SGD基础上增加二阶动量。
m t = g t m_t=g_t mt=gt
二阶动量 V 使用指数滑动平均值计算: V t = β ∗ V t − 1 + ( 1 + β ) ∗ g t 2 :表示过去一段时间的平均值 二阶动量V使用指数滑动平均值计算:V_t=β*V_{t-1}+(1+β)*g^2_t:表示过去一段时间的平均值 二阶动量V使用指数滑动平均值计算:Vt=β∗Vt−1+(1+β)∗gt2:表示过去一段时间的平均值
η t = l r ∗ m t V t = l r ∗ g t β ∗ V t − 1 + ( 1 − β ) ∗ g t 2 η_t=lr*\frac{m_t}{\sqrt{V_t}}=lr*\frac{g_t}{\sqrt{β*V_{t-1}+(1-β)*g^2_t}} ηt=lr∗Vtmt=lr∗β∗Vt−1+(1−β)∗gt2gt
参数更新公式: w t + 1 = w t − η t = w t − l r ∗ g t β ∗ V t − 1 + ( 1 − β ) ∗ g t 2 参数更新公式:w_{t+1}=w_t-η_t=w_t-lr*\frac{g_t}{\sqrt{β*V_{t-1}+(1-β)*g^2_t}} 参数更新公式:wt+1=wt−ηt=wt−lr∗β∗Vt−1+(1−β)∗gt2gt
# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
# 导入所需模块
import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np
import time ##1##
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
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)
# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
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 # 学习率为0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
##########################################################################
v_w, v_b = 0, 0
beta = 0.9
##########################################################################
# 训练部分
now_time = time.time() ##2##
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.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.square(grads[0])
v_b = beta * v_b + (1 - beta) * tf.square(grads[1])
w1.assign_sub(lr * grads[0] / tf.sqrt(v_w))
b1.assign_sub(lr * grads[1] / tf.sqrt(v_b))
##########################################################################
# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all / 4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time = time.time() - now_time ##3##
print("total_time", total_time) ##4##
# 绘制 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()
Epoch 488, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 489, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 490, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 491, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 492, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 493, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 494, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 495, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 496, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 497, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 498, loss: nan
Test_acc: 0.36666666666666664
--------------------------
Epoch 499, loss: nan
Test_acc: 0.36666666666666664
--------------------------
total_time 7.99013352394104
发现这次的图像与之前的不太一样,调小学斜率可以解决这个问题,把学斜率从1.0下调到0.4。再运行。
.
.
.
Epoch 488, loss: 0.021725745406001806
Test_acc: 1.0
--------------------------
Epoch 489, loss: 0.021718584932386875
Test_acc: 1.0
--------------------------
Epoch 490, loss: 0.021711453213356435
Test_acc: 1.0
--------------------------
Epoch 491, loss: 0.021704336628317833
Test_acc: 1.0
--------------------------
Epoch 492, loss: 0.021697248797863722
Test_acc: 1.0
--------------------------
Epoch 493, loss: 0.02169015572872013
Test_acc: 1.0
--------------------------
Epoch 494, loss: 0.021683097234927118
Test_acc: 1.0
--------------------------
Epoch 495, loss: 0.021676044445484877
Test_acc: 1.0
--------------------------
Epoch 496, loss: 0.021669025998562574
Test_acc: 1.0
--------------------------
Epoch 497, loss: 0.02166200859937817
Test_acc: 1.0
--------------------------
Epoch 498, loss: 0.021655009244568646
Test_acc: 1.0
--------------------------
Epoch 499, loss: 0.021648029913194478
Test_acc: 1.0
--------------------------
total_time 8.105649471282959
同时引入了SGDM的一阶动量和RMSProp二阶动量。
m t = β 1 ∗ m t − 1 + ( 1 − β 1 ) ∗ g t m_t=β_1*m_{t-1}+(1-β_1)*g_t mt=β1∗mt−1+(1−β1)∗gt
修正一阶动量的偏差: m t ^ = m t 1 − β 1 t 修正一阶动量的偏差:\widehat{m_t}=\frac{m_t}{1-β^t_1} 修正一阶动量的偏差:mt =1−β1tmt
V t = β 2 ∗ V s t e p − 1 + ( 1 − β 2 ) ∗ g t 2 V_t=β_2*V_{step-1}+(1-β_2)*g^2_t Vt=β2∗Vstep−1+(1−β2)∗gt2
修正二阶动量的偏差: V t ^ = m t 1 − β 2 t 修正二阶动量的偏差:\widehat{V_t}=\frac{m_t}{1-β^t_2} 修正二阶动量的偏差:Vt =1−β2tmt
η t = l r ∗ m t ^ V t ^ = l r ∗ m t 1 − β 1 t / V t 1 − β 2 t η_t=lr*\frac{\widehat{m_t}}{\sqrt{\widehat{V_t}}}=lr*\frac{m_t}{1-β^t_1}/\sqrt{\frac{V_t}{1-β^t_2}} ηt=lr∗Vt mt =lr∗1−β1tmt/1−β2tVt
参数更新公式: w t + 1 = w t + η t = w t − l r ∗ m t 1 − β 1 t / V t 1 − β 2 t 参数更新公式:w_{t+1}=w_t+η_t=w_t-lr*\frac{m_t}{1-β^t_1}/\sqrt{\frac{V_t}{1-β^t_2}} 参数更新公式:wt+1=wt+ηt=wt−lr∗1−β1tmt/1−β2tVt
# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
# 导入所需模块
import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np
import time ##1##
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
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)
# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
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 # 学习率为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, m_b = 0, 0
v_w, v_b = 0, 0
beta1, beta2 = 0.9, 0.999
delta_w, delta_b = 0, 0
global_step = 0
##########################################################################
# 训练部分
now_time = time.time() ##2##
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
##########################################################################
global_step += 1
##########################################################################
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.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.square(grads[0])
v_b = beta2 * v_b + (1 - beta2) * tf.square(grads[1])
m_w_correction = m_w / (1 - tf.pow(beta1, int(global_step)))
m_b_correction = m_b / (1 - tf.pow(beta1, int(global_step)))
v_w_correction = v_w / (1 - tf.pow(beta2, int(global_step)))
v_b_correction = v_b / (1 - tf.pow(beta2, int(global_step)))
w1.assign_sub(lr * m_w_correction / tf.sqrt(v_w_correction))
b1.assign_sub(lr * m_b_correction / tf.sqrt(v_b_correction))
##########################################################################
# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all / 4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time = time.time() - now_time ##3##
print("total_time", total_time) ##4##
# 绘制 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()
.
.
.
Epoch 488, loss: 0.0139629568438977
Test_acc: 1.0
--------------------------
Epoch 489, loss: 0.013959497911855578
Test_acc: 1.0
--------------------------
Epoch 490, loss: 0.013956061913631856
Test_acc: 1.0
--------------------------
Epoch 491, loss: 0.013952645822428167
Test_acc: 1.0
--------------------------
Epoch 492, loss: 0.013949236366897821
Test_acc: 1.0
--------------------------
Epoch 493, loss: 0.013945839717052877
Test_acc: 1.0
--------------------------
Epoch 494, loss: 0.013942447141744196
Test_acc: 1.0
--------------------------
Epoch 495, loss: 0.013939081109128892
Test_acc: 1.0
--------------------------
Epoch 496, loss: 0.01393572788219899
Test_acc: 1.0
--------------------------
Epoch 497, loss: 0.01393237872980535
Test_acc: 1.0
--------------------------
Epoch 498, loss: 0.013929049717262387
Test_acc: 1.0
--------------------------
Epoch 499, loss: 0.013925729785114527
Test_acc: 1.0
--------------------------
total_time 8.95842695236206
借鉴论文:ADAM: A METHOD FOR STOCHASTIC OPTIMIZATION
参数解读:
g t ⨀ g t : 两个向量逐个元素的乘积 t : 步数 α :学习率 θ :参数 f ( θ ) : 目标函数 , 也就是损失函数 g t : 梯度,对目标函数求导 ∂ f ∂ θ β 1 :一阶矩衰减系数 ( 指数衰减系数 ) β 2 :二阶矩指数衰减系数 m t : 一阶矩 ( g t 的均值 ) v t : 二阶矩 ( g t 的方差 ) m t ^ : m t 偏执矫正 v t ^ : v t 的偏执矫正 {gt}\bigodot{gt}:两个向量逐个元素的乘积\\t:步数\\α:学习率\\θ:参数\\f(θ):目标函数,也就是损失函数\\g_t:梯度,对目标函数求导\frac{\partial f}{\partial θ}\\β1:一阶矩衰减系数(指数衰减系数)\\β2:二阶矩指数衰减系数\\m_t:一阶矩(g_t的均值)\\v_t:二阶矩(g_t的方差)\\\widehat{m_t}:m_t偏执矫正\\\widehat{v_t}:v_t的偏执矫正 gt⨀gt:两个向量逐个元素的乘积t:步数α:学习率θ:参数f(θ):目标函数,也就是损失函数gt:梯度,对目标函数求导∂θ∂fβ1:一阶矩衰减系数(指数衰减系数)β2:二阶矩指数衰减系数mt:一阶矩(gt的均值)vt:二阶矩(gt的方差)mt :mt偏执矫正vt :vt的偏执矫正
算法解析:
t ← t + 1 : 更新步数 g t ← ∇ θ f t ( θ t − 1 ) : 求梯度 m t ← β 1 ∗ m − 1 + ( 1 − β 1 ) ∗ g t : 求一阶矩,也就是过往梯度与当前梯度的均值 , m t − 1 是前一步的均值, g t 是当前的梯度 物理意义上是计算一阶动量,类似平滑,通过保持这个匀速直线运动方向上的惯性,来使得一阶矩的更新 v t ← β 2 ∗ v t − 1 + ( 1 − β 2 ) ∗ g t 2 :求二阶矩,也就是过往梯度的平滑与当前梯度平方的均值,也就是转动惯量的持续平滑 m t ^ ← m t 1 − β 1 t v t ^ ← v t 1 − β 2 t 对 m t 和 v t 的一个矫正,随时间的增大分数值越来越小,相当于学习率,学习的步长越来越小 θ t ← θ t − 1 − α ∗ m t ^ v t ^ + ϵ : 更新参数 θ , ϵ 是为了防止分母为 0 , t\leftarrow{t+1}:更新步数\\ g_t\leftarrow{∇_θf_t(θ_{t-1})}:求梯度\\ m_t\leftarrow{β_1*m-1+(1-β_1)*g_t}:求一阶矩,也就是过往梯度与当前梯度的均值,m_{t-1}是前一步的均值,g_t是当前的梯度\\ 物理意义上是计算一阶动量,类似平滑,通过保持这个匀速直线运动方向上的惯性,来使得一阶矩的更新\\ v_t\leftarrowβ_2*v_{t-1}+(1-β_2)*g_t^2:求二阶矩,也就是过往梯度的平滑与当前梯度平方的均值,也就是转动惯量的持续平滑\\\widehat{m_t}\leftarrow{\frac{m_t}{1-β_1^t}} \\\widehat{v_t}\leftarrow{\frac{v_t}{1-β_2^t}}\\ 对m_t和v_t的一个矫正,随时间的增大分数值越来越小,相当于学习率,学习的步长越来越小\\ θ_t\leftarrowθ_{t-1}-{\frac{α*\widehat{m_t}}{\sqrt{\widehat{v_t}}+ϵ}}:更新参数θ,ϵ是为了防止分母为0, t←t+1:更新步数gt←∇θft(θt−1):求梯度mt←β1∗m−1+(1−β1)∗gt:求一阶矩,也就是过往梯度与当前梯度的均值,mt−1是前一步的均值,gt是当前的梯度物理意义上是计算一阶动量,类似平滑,通过保持这个匀速直线运动方向上的惯性,来使得一阶矩的更新vt←β2∗vt−1+(1−β2)∗gt2:求二阶矩,也就是过往梯度的平滑与当前梯度平方的均值,也就是转动惯量的持续平滑mt ←1−β1tmtvt ←1−β2tvt对mt和vt的一个矫正,随时间的增大分数值越来越小,相当于学习率,学习的步长越来越小θt←θt−1−vt +ϵα∗mt :更新参数θ,ϵ是为了防止分母为0,
更新参数θ的过程,就好比在崎岖不平的山路上开越野车,那么一阶矩就是控制的方向盘往前开,实现动量的平滑,因为动量就是衡量物体在一个直线运动方向上保持运动的趋势, 二阶矩就是控制左右旋转方向,或者说利用惯性让车往左右转的时候更加平滑,也就是在利用旋转惯性。
指数衰减的这个β1、β2这两个系数的作用是让它开始的时候调整的快,那快到目的地的时候,逐步的越来越慢。