TensorFlow2学习五之神经网络优化过程

一、函数

tf.where(条件语句,真返回A, 假返回B)

条件语句真返回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:", c)

c: tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)

np.random.RandomState.rand(n)

返回一个[0,1)之间的随机数,若n为空则返回标量。

rdm = np.random.RandomState(seed=1)
a = rdm.rand()
b = rdm.rand(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(数组1, 数组2)

将两个数组按垂直方向叠加

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.vstack((a, b))

[[1 2 3]
[4 5 6]]

np.mgrid[]、x.ravel()、np.c_[]

np.mgrid[ 起始值 : 结束值 : 步长 ,起始值 : 结束值 : 步长 , … ]

x.ravel( ) 将x变为一维数组,“把 . 前变量拉直”

np.c_[ 数组1,数组2, … ] # 使返回的间隔数值点配对

# 生成等间隔数值点
x, y = np.mgrid[1:3:1, 2:4:0.5]
# 将x, y拉直,并合并配对为二维张量,生成二维坐标点
grid = np.c_[x.ravel(), y.ravel()]
print("x:\n", x)
print("y:\n", y)
print("x.ravel():\n", x.ravel())
print("y.ravel():\n", y.ravel())
print('grid:\n', grid)
x:
 [[1. 1. 1. 1.]
 [2. 2. 2. 2.]]
y:
 [[2.  2.5 3.  3.5]
 [2.  2.5 3.  3.5]]
x.ravel():
 [1. 1. 1. 1. 2. 2. 2. 2.]
y.ravel():
 [2.  2.5 3.  3.5 2.  2.5 3.  3.5]
grid:
 [[1.  2. ]
 [1.  2.5]
 [1.  3. ]
 [1.  3.5]
 [2.  2. ]
 [2.  2.5]
 [2.  3. ]
 [2.  3.5]]

二、神经网络复杂度

神经网络复杂度多用神经网络层数和神经网络参数的个数表示。

空间复杂度

在这里插入图片描述

层数 = 隐藏层的层数 + 1个输出层
(上图为2层神经网络)

总参数 = 总w + 总b
(上图34+4 + 42+2 = 26)

时间复杂度

乘加运算次数
(上图34 + 42 = 20)

指数衰减学习率

指数衰减学习率是先使用较大的学习率来快速得到一个较优的解,然后随着迭代的继续,逐步减小学习率,使得模型在训练后期 更加稳定。指数型学习率衰减法是最常用的衰减方法,在大量模型中都广泛使用。

指数衰减学习率 = 初始学习率 * 学习率衰减率( 当前轮数 / 多少轮衰减一次 )

激活函数

激活函数是用来加入非线性因素的,因为线性模型的表达能力不够。引入非线性激活函数,可使深层神经网络的表达能力更加强大。

常见的激活函数有:sigmoid,tanh,ReLU,Leaky ReLU,PReLU,RReLU, ELU(Exponential Linear Units),softplus,softsign,softmax等,下面介绍几个典型的激活函数

优秀的激活函数:

  • 非线性: 激活函数非线性时,多层神经网络可逼近所有函数
  • 可微性: 优化器大多用梯度下降更新参数
  • 单调性: 当激活函数是单调的,能保证单层网络的损失函数是凸函数
  • 近似恒等性: f(x)≈x当参数初始化为随机小值时,神经网络更稳定

激活函数输出值的范围

  • 激活函数输出为有限值时,基于梯度的优化方法更稳定
  • 激活函数输出为无限值时,建议调小学习率

Sigmoid函数

tf.nn. sigmoid(x)

  1. 易造成梯度消失
  2. 输出非0均值,收敛慢
  3. 幂运算复杂,训练时间长
    在这里插入图片描述

Tanh函数

tf.math. tanh(x)

  1. 输出是0均值
  2. 易造成梯度消失
  3. 幂运算复杂,训练时间长

在这里插入图片描述

Relu函数

tf.nn.relu(x)

优点:

  1. 解决了梯度消失问题 (在正区间)
  2. 只需判断输入是否大于0,计算速度快
  3. 收敛速度远快于sigmoid和tanh

缺点:

  1. 输出非0均值,收敛慢
  2. Dead RelU问题:某些神经元可能永远不会
    被激活,导致相应的参数永远不能被更新。

在这里插入图片描述

Leaky Relu函数

tf.nn.leaky_relu(x)

Leaky Relu有Relu的所有优点,外加不会有Dead Relu问题,但是在实际操作当中,并没有完全证明Leaky Relu总是好于Relu。

在这里插入图片描述

损失函数(loss)

预测值(y)与已知答案(y_)的差距

神经网络优化目标:loss最小

均方误差损失函数

均方误差(Mean Square Error)是回归问题最常用的损失函数。回归问题解决的是对具体数值的预测,比如房价预测、销量预测等。这些问题需要预测的不是一个事先定义好的类别,而是一个任意实数。均方误差定义如下:
在这里插入图片描述

其中yi为一个batch中第i个数据的真实值,而yi导为神经网络的预测值。

loss_mse = tf.reduce_mean(tf.square(y_ - y))

交叉熵损失函数

交叉熵(Cross Entropy)表征两个概率分布之间的距离,交叉熵越小说明二者分布越接近,是分类问题中使用较广泛的损失函数。
在这里插入图片描述

其中 代表数据的真实值, 代表神经网络的预测值。

tf.losses.categorical_crossentropy(y_,y)
loss_ce1 = tf.losses.categorical_crossentropy([1, 0], [0.6, 0.4])
loss_ce2 = tf.losses.categorical_crossentropy([1, 0], [0.8, 0.2])
print("loss_ce1:", loss_ce1)
print("loss_ce2:", loss_ce2)
loss_ce1: tf.Tensor(0.5108256, shape=(), dtype=float32)
loss_ce2: tf.Tensor(0.22314353, shape=(), dtype=float32)

对于多分类问题,神经网络的输出一般不是概率分布,因此需要引入softmax层,使得输出服从概率分布。TensorFlow中可计算交叉熵损失函数的API有:

TensorFlow API: tf.keras.losses.categorical_crossentropy TensorFlow API: tf.nn.softmax_cross_entropy_with_logits
TensorFlow API: tf.nn.sparse_softmax_cross_entropy_with_logits

自定义损失函数

根据具体任务和目的,可设计不同的损失函数。从老师课件和讲解中对于酸奶预测损失函数的设计,我们可以得知损失函数的定义能极大影响模型预测效果。好的损失函数设计对于模型训练能够起到良好的引导作用。

loss_zdy = tf.reduce_sum(tf.where(tf.greater(y,y_),COST(y-y_),PROFIT(y_-y)))

过拟合与欠拟合

欠拟合的解决方法:

  • 增加输入特征项
  • 增加网络参数
  • 减少正则化参数

过拟合的解决方法:

  • 数据清洗
  • 增大训练集
  • 采用正则化
  • 增大正则化参数

正则化缓解过拟合

正则化在损失函数中引入模型复杂度指标,利用给W加权值,弱化了训练数据的噪声(一般不正则化b)

正则化的选择

L1正则化大概率会使很多参数变为零,因此该方法可通过稀疏参数,即减少参数的数量,降低复杂度。
L2正则化会使参数很接近零但不为零,因此该方法可通过减小参数值的大小降低复杂度

神经网络参数优化器

优化算法可以分成一阶优化和二阶优化算法,其中一阶优化就是指的梯度算法及其变种,而二阶优化一般是用二阶导数(Hessian 矩阵)来计算,如牛顿法,由于需要计算Hessian阵和其逆矩阵,计算量较大,因此没有流行开来。这里主要总结一阶优化的各种梯度下降方法。

在这里插入图片描述一阶动量:与梯度相关的函数
二阶动量:与梯度平方相关的函数

1. SGD(无momentum)

在这里插入图片描述

w1.assign_sub(lr * grads[0])  # 参数w1自更新
b1.assign_sub(lr * grads[1])  # 参数b自更新

2. SGDM(含momentum的SGD)

在SGD基础上增加一阶动量。

在这里插入图片描述

# 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)

3. Adagrad

在SGD基础上增加二阶动量
在这里插入图片描述

# 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))

4. RMSProp

SGD基础上增加二阶动量

在这里插入图片描述

# 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))

5. Adam

同时结合SGDM一阶动量和RMSProp二阶动量

在这里插入图片描述在这里插入图片描述

# 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))

猜你喜欢

转载自blog.csdn.net/qq_41754907/article/details/112861537