TensorFlow API: tf.keras.optimizers.schedules.ExponentialDecay
指数衰减学习率 = 初始学习率 * 学习率衰减率(当前轮数/多少轮衰减一次)
# 手动实现
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):
lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)
# 其他代码
TensorFlow API:tf.optimizers.schedules.PiecewiseConstantDecay
优秀的激活函数应满足:
激活函数输出值的范围:
TensorFlow API:tf.math.sigmoid
优点:
缺点:
TensorFlow API:tf.math.tanh
优点:
缺点:
TensorFlow API:tf.nn.relu
优点:
缺点:
TensorFlow API:tf.nn.leaky_relu
理论上来讲,Leaky ReLU有ReLU的所有优点,外加不会有Dead ReLU问题,但是在实际操作当 中,并没有完全证明Leaky ReLU总是好于ReLU。
TensorFlow API:tf.nn.softmax
TensorFlow API:tf.keras.losses.MSE
TensorFlow API:tf.keras.losses.categorical_crossentropy(y_true, y_pred, from_logits=False, label_smoothing=0)
y_true: 真实值.
y_pred: 预测值.
from_logits: y_pred是否为logits张量.
label_smoothing: [0,1]之间的小数.
TensorFlow API:tf.nn.softmax_cross_entropy_with_logits(labels, logits, axis=-1, name=None)
softmax与交叉熵结合使用
logits经过softmax后,与labels进行交叉熵计算.。
TensorFlow API:tf.nn.sparse_softmax_cross_entropy_with_logits(labels, logits, name=None)
labels先进行one-hot编码,logits先进行softmax,之后两者进行交叉熵计算。
均方误差损失函数MSE认为 “y比y_大1” 和 “y比y_小1” 这两种情况的误差相同,然而实际情况往往不是这样,例如比销售量多生产一件商品损失的是生产成本,而比销售量少生产一件商品损失的是一件商品的利润。因此,可以根据实际情况自定义损失函数。
定义:待优化参数w, 损失函数loss,学习率lr,每次迭代一个batch,t表示当前batch迭代的总次数:
一阶动量:与梯度相关的函数
二阶动量:与梯度平方相关的函数
在上面的四个步骤中,3,4基本上是不变的,不同的优化器定义了不同的一阶动量mt和二阶动量vt
TensorFlow API: tf.keras.optimizers.SGD
原始的SGD
一阶动量mt=梯度gt
二阶动量vt=1
所以:::::::::::
η = lr * mt / 1 = lr * gt
w = w - lr * gt
w1.assign_sub(learning_rate * grads[0])
b1.assign_sub(learning_rate * grads[1])
引入了动量的SGD
一阶动量mt=βmt-1 + (1-β)gt
二阶动量vt=1
所以:::::::::::
η = lr * mt / 1 = lr * (βmt-1 + (1-β)gt)
w = w - lr * (βmt-1 + (1-β)gt)
# sgd-momentun
beta = 0.9
m_w = beta * m_w + (1 - beta) * grads[0]
m_b = beta * m_b + (1 - beta) * grads[1]
w1.assign_sub(learning_rate * m_w)
b1.assign_sub(learning_rate * m_b)
TensorFlow API:tf.keras.optimizers.Adagrad
此引入二阶动量:所有梯度值的平方和
一阶动量mt=gt
二阶动量vt=∑gt2
所以:::::::::::
η = lr * gt / (∑gt2)0.5
w = w - lr * gt / (∑gt2)0.5
# adagrad
v_w += tf.square(grads[0])
v_b += tf.square(grads[1])
w1.assign_sub(learning_rate * grads[0] / tf.sqrt(v_w))
b1.assign_sub(learning_rate * grads[1] / tf.sqrt(v_b))
TensorFlow API: tf.keras.optimizers.RMSprop
由于 AdaGrad 的学习率衰减太过激进,考虑改变二阶动量的计算策略:不 累计全部梯度,只关注过去某一窗口内的梯度。
一阶动量mt=gt
二阶动量vt=β2vt-1 + (1-β2)gt2
所以:::::::::::
η = lr * gt / (β2vt-1 + (1-β2)gt2)0.5
w = w - lr * gt / (β2vt-1 + (1-β2)gt2)0.5
beta = 0.9
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(learning_rate * grads[0] / tf.sqrt(v_w))
b1.assign_sub(learning_rate * grads[1] / tf.sqrt(v_b))
TensorFlow API: tf.keras.optimizers.Adam
Adam将Momentum和RMSProp结合起来,既有一阶动量又有二阶动量。
一阶动量mt=βmt-1 + (1-β)gt
二阶动量vt=β2vt-1 + (1-β2)gt2
一阶动量和二阶动量都是按照指数移动平均值进行计算的。初始化m0=0,v0=0 ,在初期,迭代得到的会接近于0。我们可以通过对mt,vt进行偏差修正
来解决这一问题。
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(learning_rate * m_w_correction / tf.sqrt(v_w_correction))
b1.assign_sub(learning_rate * m_b_correction / tf.sqrt(v_b_correction))
优化器 | 一阶动量mt | 二阶动量vt | η = lr * mt / vt2/1 | w = w - η | |
---|---|---|---|---|---|
vanilla SGD | gt | 1 | lr * gt | w = w - lr *gt | |
SGD with Momentum | βmt-1 + (1-β)gt | 1 | lr * βmt-1 + (1-β)gt | w = w - lr * βmt-1 + (1-β)gt | |
AdaGrad | gt | ∑gt2 | lr * gt / (∑gt2)0.5 | w = w - lr * gt / (∑gt2)0.5 | |
RMSProp | gt | β2vt-1 + (1-β2)gt2 | lr * gt / (β2vt-1 + (1-β2)gt2)0.5 | w = w - lr * gt / (β2vt-1 + (1-β2)gt2)0.5 | |
Adam | βmt-1 + (1-β)gt | β2vt-1 + (1-β2)gt2 | 加入偏差修正 |
tf.where(condition, x, y) 根据condition,取x或y中的值。如果condition为True,对应位置取x的值;如果condition为 False,对应位置取y的值。很类似于c语言中的三元运算符:condition?x,y
np.random.RandomState.rand(维度) 返回一个[0,1)之间的随机数
np.vstack()将两个数组按垂直方向叠加
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[起始值:结束值:步长 ,起始值:结束值:步长 , ],这个函数不太该理解,结合着例子看
x, y = np.mgrid[1:3:1, 2:4:0.5]
print("x:\n", x)
print("y:\n", y)
# x:
# [[1. 1. 1. 1.]
# [2. 2. 2. 2.]]
# y:
# [[2. 2.5 3. 3.5]
# [2. 2.5 3. 3.5]]
要保证返回的两个(多个数组维度相同),第一个参数(1:3:1)决定行数为2,第二个参数(2:4:0.5)决定列数为4。
x.ravel() 将x变为一维数组,“把x变量拉直”
#接上一段代码
x1=x.ravel()
y1=y.ravel()
# x1:
# [1. 1. 1. 1. 2. 2. 2. 2.]
# y1:
# [2. 2.5 3. 3.5 2. 2.5 3. 3.5]
np.c_[ ] 使返回的间隔数值点配对
np.c_[ 数组1,数组2, … ]
#接上一段代码
grid = np.c_[x1, y1]
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]]
两个数组的值一一配对。