机器学习笔记2-1:逻辑回归

*注:本博客参考李宏毅老师2020年机器学习课程. 视频链接


1 逻辑回归

1.1 概念

从上一节的讨论中,我们发现对一个具有特征值 X X X的个体,如果 X X X的各分量相互独立,并且每一个 X X X也是独立同分布的话,那么对这个个体进行分类,其属于某一个类别的概率 f ( x ) f(x) f(x)可以表示为:
f ( x ) = g ( z ) = 1 1 + e − z , z = b + ∑ w i x i (1) f(x)=g(z)=\frac{1}{1+e^{-z}},z=b+\sum{w_ix_i}\tag{1} f(x)=g(z)=1+ez1,z=b+wixi(1)
易得 g ( z ) ∈ ( 0 , 1 ) g(z)\in(0,1) g(z)(0,1)。既然如此,那么也可以通过与线性回归类似的方式来使用梯度下降算法,让计算机自动求解w和b。这类问题就称为逻辑回归问题。

1.2 损失函数

在线性回归中,我们使用了均方差作为损失函数,而逻辑回归需要使用另一种损失函数——交叉熵。


交叉熵是这样产生的:假设有两个类Class 1和Class 2,对于数据集中某一个体的特征值 X i X_i Xi,当个体属于Class 1时,其产生的概率为 1 − f ( x i ) 1-f(x_i) 1f(xi),个体属于Class 2时,其产生的概率为 f ( x i ) f(x_i) f(xi)。由于所有个体的产生概率相互独立,因此如果计算每一个个体产生的概率,再将它们相乘,就可以得到整个数据集产生的概率。若分类模型使得整个数据集产生概率最大,那么这个分类模型被认为是准确的。因此可以定义L如下:
L ( f ) = f ( x 1 ) f ( x 2 ) ( 1 − f ( x 3 ) ) . . . f ( x n ) L(f)=f(x_1)f(x_2)(1-f(x_3))...f(x_n) L(f)=f(x1)f(x2)(1f(x3))...f(xn)
对上式左右两边取自然对数,不改变其单调性,因此得:
ln ⁡ L ( f ) = ln ⁡ f ( x 1 ) + ln ⁡ f ( x 2 ) + ln ⁡ ( 1 − f ( x 3 ) ) + . . . ln ⁡ f ( x n ) \ln{L(f)}=\ln{f(x_1)}+\ln{f(x_2)}+\ln{(1-f(x_3))}+...\ln{f(x_n)} lnL(f)=lnf(x1)+lnf(x2)+ln(1f(x3))+...lnf(xn)

上式的格式不统一,因为对于类别不同的个体需要分别使用两种不同的计算方式,于是约定当个体属于Class 1时, y ^ = 1 \hat{y}=1 y^=1,个体属于Class 2时, y ^ = 0 \hat{y}=0 y^=0。上式可以写成:
ln ⁡ L ( f ) = ( y 1 ^ ln ⁡ f ( x 1 ) + ( 1 − y 1 ^ ) ln ⁡ ( 1 − f ( x 1 ) ) ) + ( y 2 ^ ln ⁡ f ( x 2 ) + ( 1 − y 2 ^ ) ln ⁡ ( 1 − f ( x 2 ) ) ) + ( y 3 ^ ln ⁡ f ( x 3 ) + ( 1 − y 3 ^ ) ln ⁡ ( 1 − f ( x 3 ) ) ) + . . . + ( y n ^ ln ⁡ f ( x n ) + ( 1 − y n ^ ) ln ⁡ ( 1 − f ( x n ) ) ) \begin{aligned} \ln{L(f)}&=(\hat{y_1}\ln{f(x_1)}+(1-\hat{y_1})\ln{(1-f(x_1))})\\ &+(\hat{y_2}\ln{f(x_2)}+(1-\hat{y_2})\ln{(1-f(x_2))})\\ &+(\hat{y_3}\ln{f(x_3)}+(1-\hat{y_3})\ln{(1-f(x_3))})\\ &+...\\ &+(\hat{y_n}\ln{f(x_n)}+(1-\hat{y_n})\ln{(1-f(x_n))})\\ \end{aligned} lnL(f)=(y1^lnf(x1)+(1y1^)ln(1f(x1)))+(y2^lnf(x2)+(1y2^)ln(1f(x2)))+(y3^lnf(x3)+(1y3^)ln(1f(x3)))+...+(yn^lnf(xn)+(1yn^)ln(1f(xn)))
ln ⁡ L ( f ) \ln{L(f)} lnL(f)的值越大,则分类模型越好。但是损失函数要求值越小,代表模型越好,于是取 ln ⁡ L ( f ) \ln{L(f)} lnL(f)的相反数,得:
L o s s ( f ) = − ln ⁡ L ( f ) = − ln ⁡ L ( g ) = − ∑ ( y ^ ln ⁡ g ( z ) + ( 1 − y ^ ) ln ⁡ ( 1 − g ( z ) ) ) (2) Loss(f)=-\ln{L(f)}=-\ln{L(g)}=-\sum{(\hat{y}\ln{g(z)}+(1-\hat{y})\ln{(1-g(z))})} \tag{2} Loss(f)=lnL(f)=lnL(g)=(y^lng(z)+(1y^)ln(1g(z)))(2)
这就是交叉熵的定义。在上式中,由于 g ( z ) ∈ ( 0 , 1 ) g(z)\in(0,1) g(z)(0,1),因此 ln ⁡ g ( z ) ∈ ( − ∞ , 0 ] \ln{g(z)}\in(-\infty,0] lng(z)(,0],而 ln ⁡ ( 1 − g ( z ) ) ∈ ( 0 , ∞ ) \ln{(1-g(z))}\in(0,\infty) ln(1g(z))(0,)

1.3 梯度下降

对式2求导,则有:
∂ L o s s ∂ w i = ∂ L o s s ∂ g ( z ) ∂ g ( z ) ∂ z ∂ z ∂ w i ∂ L o s s ∂ g ( z ) = ∑ ( 1 − y ^ 1 − g ( z ) − y ^ g ( z ) ) ∂ g ( z ) ∂ z = g ( z ) ( 1 − g ( z ) ) ∂ z ∂ w i = x i \begin{aligned} \frac{\partial{Loss}}{\partial{w_i}}&=\frac{\partial{Loss}}{\partial{g(z)}}\frac{\partial{g(z)}}{\partial{z}}\frac{\partial{z}}{\partial{w_i}}\\ \frac{\partial{Loss}}{\partial{g(z)}}&=\sum{(\frac{1-\hat{y}}{1-g(z)}-\frac{\hat{y}}{g(z)})}\\ \frac{\partial{g(z)}}{\partial{z}}&=g(z)(1-g(z))\\ \frac{\partial{z}}{\partial{w_i}}&=x_i \end{aligned} wiLossg(z)Losszg(z)wiz=g(z)Losszg(z)wiz=(1g(z)1y^g(z)y^)=g(z)(1g(z))=xi
整理得:
∂ L o s s ∂ w i = ∑ ( g ( z ) − y ^ ) x i (3) \frac{\partial{Loss}}{\partial{w_i}}=\sum{(g(z)-\hat{y})x_i}\tag{3} wiLoss=(g(z)y^)xi(3)
如果对 w i w_i wi进行参数更新,其过程是这样的:
w i t + 1 = w i t − η ∑ ( g ( z ) − y ^ ) x i (4) w_i^{t+1}=w_i^t-\eta\sum{(g(z)-\hat{y})x_i}\tag{4} wit+1=witη(g(z)y^)xi(4)
从式4可以看出,参数 w i w_i wi更新得速度取决于三个值:

  1. 学习率 η \eta η的大小;
  2. 参数 w i w_i wi本身的大小;
  3. 模型计算所得属于某个类别的概率与实际情况的差距。

下面使用逻辑回归的方法对2_1节中的问题进行拟合,结果如下:

from models.simple_regression_model import Logistic_Regression as Model
import numpy as np
from datas.hws_data import get_data
train, test = get_data()
m = Model(1)
m.train(train[:, :2], train[:, 2], lr=1, epoch=40000)
m.show()
l = (np.abs(np.around(m.forward(test[:, :2]))-test[:, 2])).sum()
print("准确率:{:.2f}%".format(100-l/test.shape[0]*100))

y=[-12.67 -12.6 ]+[0.07 0.23]x
abs loss: 22.553192817202635 
准确率:89.00%

与2_0节一样,可以做出分界线如下:

import matplotlib.pyplot as plt
B = -(m.w[0].sum()/m.w[1][1])
A = -m.w[1][0]/m.w[1][1]
xx = np.linspace(100, 200)
s=20
plt.ylim(train[:,1].min()-5,train[:,1].max()+5)
plt.xlim(train[:,0].min()-5,train[:,0].max()+5)
plt.plot(xx, A*xx+B)
plt.scatter(train[train[:, 2] == 1][:, 0], train[train[:, 2] == 1]
            [:, 1], c="green", label="males_train", s=s)
plt.scatter(train[train[:, 2] == 0][:, 0], train[train[:, 2] == 0]
            [:, 1], c="orange", label="females_train", s=s)
plt.legend()
plt.show()
plt.ylim(test[:,1].min()-5,test[:,1].max()+5)
plt.xlim(test[:,0].min()-5,test[:,0].max()+5)
plt.plot(xx, A*xx+B)
plt.scatter(test[test[:, 2] == 1][:, 0], test[test[:, 2] == 1]
            [:, 1], c="green", label="males_test", s=s)
plt.scatter(test[test[:, 2] == 0][:, 0], test[test[:, 2] == 0]
            [:, 1], c="orange", label="females_test", s=s)
plt.legend()
plt.show()

2 为什么不使用均方差作为损失函数

在逻辑回归中,我们使用了交叉熵作为损失函数。但是既然逻辑回归和线性回归都是回归问题,为什么不使用线性回归中常用的均方差作为损失函数呢?
我们可以从两个函数的图像得到直观的解释:

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
w1 = np.linspace(-5, 5)
w2 = np.linspace(-5, 5)
w1, w2 = np.meshgrid(w1, w2)
z = w1*1+w2*1
y1 = 1/(1+np.exp(-z))


def MSE(y1, y):
    return (y1-y)**2


def CE(y1, y):
    return -(y*np.log(y1)+(1-y)*np.log(1-y1))


ax.plot_wireframe(w1, w2, MSE(y1, 0), rstride=3, cstride=3, color="red",label="MSE")
ax.plot_wireframe(w1, w2, 0.25*CE(y1, 0), rstride=3, cstride=3,label="CE")
plt.legend()
plt.show()

图中红色线条表示均方差的值随着两个参数 w 1 w_1 w1 w 2 w_2 w2的变化情况,蓝色表示交叉熵(为了方便比较,将交叉熵的大小按比例缩放为原来的1/4)。


设置y=0,x=[1,1]那么我们可以算得当 w 1 w_1 w1 w 2 w_2 w2越大,目标函数的值与y的差距越大,此时更新参数的速度应该越快,因为此时函数与目标相差较远。


然而从图中我们可以看到,均方差的表现却恰恰相反,在目标函数的值与y的差距很大时,梯度却为0,更新参数极为缓慢,这显然与我们的设想不一致,而交叉熵(蓝色曲线)则不会出现这种情况。


可以在数学上给出严格证明,这里略过。

3 多类别逻辑回归

3.1 模型调整

当需要对超过两个类别进行逻辑回归时,直接使用某一个类别的概率已经不能满足需求。这时网络的输出应该定义为每一个类别的概率,例如当对类A、B、C进行分类,则模型输出为一个三维向量,每个分量的值分别表示该个体属于类A、B、C的概率。


则可以预见的是,模型需要为每一个类别设置一组参数,每组参数与两个类别时一致。

3.2 Softmax函数

一般情况下,我们可以假设一个个体仅属于一个类别,为了更直观地得到每个类别的概率,应当满足:
1 = ∑ P ( c l a s s ) 1=\sum{P\left(class\right)} 1=P(class)
其中 P ( c l a s s ) P\left(class\right) P(class)表示个体属于某一个类别的概率,该表达式表面个体属于每个类别的概率之和为1,即个体属于且仅属于一个类别。


因此可以使用Softmax函数接在sigmoid函数之后,其定义如下:
S o f t m a x ( Z 1 ) = e z 1 ∑ i = 1 n e z i Softmax(Z_1)=\frac{e^{z_1}}{\sum_{i=1}^{n}{e^{z_i}}} Softmax(Z1)=i=1neziez1
不难得出Softmax函数的输出介于0到1之间,且各个类别的输出之和为1.


修改了目标函数之后相应的损失函数的偏导值也需要修改,但此处不再给出。

4 逻辑回归的局限与解决方案

4.1 无法分类的局限

对于一个二分类的问题,由于逻辑回归的表达式是一条直线,在一些情况下逻辑回归无法的分开两个类别。例如有如下四个个体:

显然,无法找到一条直线来区分这两个类别。

4.2 解决方案——特征提取

一种可行的解决方案是,在进行逻辑回归之前,首先对四个个体的特征值进行加工,例如,计算四个个体与(1,1)和(3,3)的距离,那么属于class 1的个体的特征值分别为:(0, 2 2 2\sqrt{2} 22 )( 2 2 2\sqrt{2} 22 ,0),而class 2的两个类别的特征值分别为:(2,2)(2,2),在图中的位置为:

显然能够找到一条直线来分开这两个类别的点。


但是提取特征也是一个需要技巧的过程,如果不能提取到合适的特征,可能还是无法清楚地分开两个类别的点。那么当我们需要使用梯度下降算法来自动求解时,应该如何提取特征呢?


先前我们已经使用到的逻辑回归模型,如果最后不经过sigmoid函数,那么其输入是一个包含特征值的向量,输出也是一个向量。如果将整个逻辑回归模型视为一个单元,那么理论上来说,一个单元的输出可以作为另一个单元的输入。那么在理想的情况下,两个相互堆叠的逻辑回归模块(第一个不经sigmoid函数)构成的模型,第一个模块将进行特征提取的工作,第二个模块进行分类工作,由此就能够实现自动求解适合用于该分类问题的模型。


这种思想正是深度学习的基本思想,将在下一节中论述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值