COURSE2 WEEK2
模型训练的细节
-
定义模型,即指定如何在给定输入特征 x x x 以及参数 w w w 和 b b b 的情况下计算输出
-
指定损失函数 L ( f w ⃗ , b ( x ⃗ ) , y ) L(f_{\vec w, b}(\vec x),y) L(fw,b(x),y)
指定成本函数 J ( w ⃗ , b ) = 1 m ∑ i = 1 m L ( f w ⃗ , b ( x ⃗ ( i ) ) , y ( i ) ) J(\vec w, b) = \frac{1}{m} \sum_{i=1}^mL(f_{\vec w, b}(\vec x^{(i)}),y^{(i)}) J(w,b)=m1∑i=1mL(fw,b(x(i)),y(i))
-
使用算法来进行训练,找到最小化成本函数对应的参数
定义模型
该步骤指定了神经网络的整个框架
- 通过
Dense
用来定义神经网络层units
表示这个层的神经元个数activation
表示使用的激活函数
- 通过
Sequential
来把各个神经网络层连接起来
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense##### 定义模型 #####
model = Sequential([Dense(units=25, activation='sigmoid'),Dense(units=15, activation='sigmoid'),Dense(units=1, activation='sigmoid')
])
指定损失函数
由于是分类任务,所以使用交叉熵函数(二元交叉熵)
使用compile()
定义
##### 定义损失函数 #####
from tensorflow.keras.losses import BinaryCrossentropymodel.compile(loss=BinaryCrossentropy())
keras
中的losses
集成了很多损失函数:
BinaryCrossentropy()
二元交叉熵损失函数MeanSquaredError()
均方误差函数
训练模型
一般而言,我们使用梯度下降来进行模型的训练
直接调用Tensorflow
中的fit
函数
##### 模型训练 #####
model.fit(X, y, epochs = 100) # epoch 为迭代次数
激活函数
常见激活函数
使用激活函数,加在每一层神经网络层之间,可以使得我们的模型具有更强大的能力
Sigmoid激活函数和Relu激活函数
加入激活函数后,可以使得我们的模型具有非线性的特点,从而使得我们的模型更加复杂,能够学习到更复杂的模型,拟合结果更加准确
激活函数的使用
对于激活函数的选择,要根据具体的输出等要适当的选择
对于输出层:
- 如果是二分类问题,可以使用Sigmoid函数
- 如果是回归任务,预测房价等,因为房价永远不会是负值,因此可以使用Relu函数
- 对于更一般的回归任务,即输出可正可负,可以使用线性激活函数
对于隐藏层:
- Relu的使用较多,且使用效果较好
使用Relu较多的原因:
- 计算比Sigmoid函数简单
- Relu函数图像只有一边比较平坦,而Sigmoid函数图像有两边比较平坦。当函数图像比较平坦时,会造成梯度下降算法较慢
多分类问题
多分类问题指的是,在分类问题中,最终输出的类别是多个,即 y y y 得输出有多个(有限)
上图左侧是二分类任务,右侧是多分类任务
注意与聚类算法地区别
- 聚类算法属于无监督学习,即没有标签
- 多分类是监督学习,有标签
Softmax函数
当分类任务是二分类时,我们可以使用Sigmoid函数作为输出层地激活函数,即最终地输出为 0 或 1
而当我们的任务是多分类任务时,这时就有多个输出的值,输出层的激活函数就要使用Softmax函数,保证我们的模型能够输出多个类别的概率
Softmax回归公式
P ( y = i ∣ x ⃗ ) = a i = e z i ∑ k = 1 N e z k P(y=i | \vec x) =a_i = \frac{e^{z_i}}{\sum_{k=1}^{N}e^{z_k}} P(y=i∣x)=ai=∑k=1Nezkezi
并且最终 ∑ k = 1 N P ( y = k ∣ x ⃗ ) = 1 \sum_{k=1}^{N}P(y=k | \vec x) = 1 ∑k=1NP(y=k∣x)=1
对于Softmax函数,最终输出的是 a 1 … a n a_1 \dots a_n a1…an 的值
成本函数
参考逻辑回归的损失函数,对于多分类任务,其损失函数为
l o s s ( a I , a 2 , … , a N , y ) = { − log a 1 i f y = 1 − log a 2 i f y = 2 ⋮ − log a N i f y = N loss(a_I, a_2, \dots ,a_N, y) = \begin{equation} \begin{cases} -\log a_1 \ \ \ \ \ if \ \ y = 1 \\ -\log a_2 \ \ \ \ \ if \ \ y = 2 \\ \vdots \\ -\log a_N \ \ \ \ \ if \ \ y = N \end{cases} \end{equation} loss(aI,a2,…,aN,y)=⎩ ⎨ ⎧−loga1 if y=1−loga2 if y=2⋮−logaN if y=N
在Tensorflow
中对应函数SparseCrossEntropy()
Softmax实现的改进
在计算机中,由于每次计算都可能会有浮点数的舍入,即存在一定的误差,因此不同的计算顺序,可能会导致得到不同的结果
例如,对于二分类的逻辑回归,如果我们按照以下方式计算:
S t e p 1 : a = g ( z ) = 1 1 + e z S t e p 2 : l o s s = − y log ( a ) − ( 1 − y ) log ( 1 − a ) Step1: \ \ a = g(z) = \frac{1}{1+e^z} \\ Step2: \ \ loss = -y\log (a) - (1-y)\log (1-a) Step1: a=g(z)=1+ez1Step2: loss=−ylog(a)−(1−y)log(1−a)
那么 a a a 作为中间值,在第一步的赋值和第二步的带入过程中,会产生精度的损失,最终会造成误差较大的结果
而,如果我们直接把 z z z 带入到损失函数里计算,即:
l o s s = − y log ( 1 1 + e z ) − ( 1 − y ) log ( 1 − 1 1 + e z ) loss = -y\log (\frac{1}{1+e^z}) - (1-y)\log (1-\frac{1}{1+e^z}) loss=−ylog(1+ez1)−(1−y)log(1−1+ez1)
这样就会避免一些误差的产生,使得我们的结果更加准确
在代码中的改变
model.compile(loss = BinaryCrossEntropy(from_logits=True))
多个输出的分类
对于一个图片里,我们要同时检测是否有人、是否有轿车、是否有公交车
对于这种多个输出的分类任务,我们可以通过一个神经网络的训练,在最后使用三个Sigmoid函数,分别用来输出是否有人,是否有轿车,是否有公交车,即转化为了一个三个二分类任务
Adam优化算法
对于传统的梯度下降算法,当其学习率较小时,会迭代较多次数,而当其学习率较大时,收敛过程中就会产生震荡,为了改进这个缺点,出现了Adam算法,可以自动的调节学习率
Adam算法并没有全局单一的使用学习率,而是将学习率自适应:
- 如果我们的梯度下降过程中参数一直朝着一个大致的方向移动,那么Adam算法就会增加学习率,加快算法的步伐
- 如果参数一致来回不断的震荡,那么Adam算法就会降低学习率,使得算法能够较好的朝收敛方向移动
Adam算法的使用
model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3),loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logts=True))