Pytorh Note11 Logistic 回归模型

Posted Real&Love

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pytorh Note11 Logistic 回归模型相关的知识,希望对你有一定的参考价值。

Pytorh Note11 Logistic 回归模型


全部笔记的汇总贴: Pytorch Note 快乐星球

Logistic 回归模型

机器学习中的监督学习主要分为回归问题和分类问题,我们之前已经讲过回归问题了,它希望预测的结果是连续的,那么分类问题所预测的结果就是离散的类别。这时输入变量可以是离散的,也可以是连续的,而监督学习从数据中学习一个分类模型或者分类决策函数,它被称为分类器(classifier)。分类器对新的输入进行输出预测,这个过程即称为分类(classification)。例如,判断邮件是否为垃圾邮件,医生判断病人是否生病,或者预测明天天气是否下雨等。同时分类问题中包括有二分类和多分类问题,我们下面先讲一下最著名的二分类算法——Logistic 回归。首先从 Logistic 回归的起源说起。

Logistic 起源于对人口数量增长情况的研究,后来又被应用到了对于微生物生长情况的研究,以及解决经济学相关的问题,现在作为回归分析的一个分支来处理分类问题,先从 Logistic 分布入手,再由 Logistic 分布推出 Logistic 回归

模型形式

Logistic 回归的模型形式和线性回归一样,都是 y = w x + b y = wx + b y=wx+b,其中 x 可以是一个多维的特征,唯一不同的地方在于 Logistic 回归会对 y 作用一个 logistic 函数,将其变为一种概率的结果。 Logistic 函数作为 Logistic 回归的核心,我们下面讲一讲 Logistic 函数,也被称为 Sigmoid 函数。

Sigmoid 函数

Sigmoid 函数非常简单,其公式如下

f ( x ) = 1 1 + e − x f(x) = \\frac{1}{1 + e^{-x}} f(x)=1+ex1

Sigmoid 函数的图像如下

在这里插入图片描述

可以看到 Sigmoid 函数的范围是在 0 ~ 1 之间,所以任何一个值经过了 Sigmoid 函数的作用,都会变成 0 ~ 1 之间的一个值,这个值可以形象地理解为一个概率,比如对于二分类问题,这个值越小就表示属于第一类,这个值越大就表示属于第二类。

另外一个 Logistic 回归的前提是确保你的数据具有非常良好的线性可分性,也就是说,你的数据集能够在一定的维度上被分为两个部分,比如

img

可以看到,上面红色的点和蓝色的点能够几乎被一个平面分割开来

回归问题 vs 分类问题

Logistic 回归处理的是一个分类问题,而上一个模型是回归模型,那么回归问题和分类问题的区别在哪里呢?

从上面的图可以看出,分类问题希望把数据集分到某一类,比如一个 3 分类问题,那么对于任何一个数据点,我们都希望找到其到底属于哪一类,最终的结果只有三种情况,{0, 1, 2},所以这是一个离散的问题。

而回归问题是一个连续的问题,比如曲线的拟合,我们可以拟合任意的函数结果,这个结果是一个连续的值。

分类问题和回归问题是机器学习和深度学习的第一步,拿到任何一个问题,我们都需要先确定其到底是分类还是回归,然后再进行算法设计

损失函数

前一节对于回归问题,我们有一个 loss 去衡量误差,那么对于分类问题,我们如何去衡量这个误差,并设计 loss 函数呢?

Logistic 回归使用了 Sigmoid 函数将结果变到 0 ~ 1 之间,对于任意输入一个数据,经过 Sigmoid 之后的结果我们记为 y ^ \\hat{y} y^,表示这个数据点属于第二类的概率,那么其属于第一类的概率就是 1 − y ^ 1-\\hat{y} 1y^。如果这个数据点属于第二类,我们希望 y ^ \\hat{y} y^ 越大越好,也就是越靠近 1 越好,如果这个数据属于第一类,那么我们希望 1 − y ^ 1-\\hat{y} 1y^ 越大越好,也就是 y ^ \\hat{y} y^ 越小越好,越靠近 0 越好,所以我们可以这样设计我们的 loss 函数

l o s s = − ( y ∗ l o g ( y ^ ) + ( 1 − y ) ∗ l o g ( 1 − y ^ ) ) loss = -(y * log(\\hat{y}) + (1 - y) * log(1 - \\hat{y})) loss=(ylog(y^)+(1y)log(1y^))

其中 y 表示真实的 label,只能取 {0, 1} 这两个值,因为 y ^ \\hat{y} y^ 表示经过 Logistic 回归预测之后的结果,是一个 0 ~ 1 之间的小数。如果 y 是 0,表示该数据属于第一类,我们希望 y ^ \\hat{y} y^ 越小越好,上面的 loss 函数变为

l o s s = − ( l o g ( 1 − y ^ ) ) loss = - (log(1 - \\hat{y})) loss=(log(1y^))

在训练模型的时候我们希望最小化 loss 函数,根据 log 函数的单调性,也就是最小化 y ^ \\hat{y} y^,与我们的要求是一致的。

而如果 y 是 1,表示该数据属于第二类,我们希望 y ^ \\hat{y} y^ 越大越好,同时上面的 loss 函数变为

l o s s = − ( l o g ( y ^ ) ) loss = -(log(\\hat{y})) loss=(log(y^))

我们希望最小化 loss 函数也就是最大化 y ^ \\hat{y} y^,这也与我们的要求一致。

所以通过上面的论述,说明了这么构建 loss 函数是合理的。

Logistic 例子

import torch
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

我们从 data.txt 读入数据,感兴趣的同学可以打开 data.txt 文件进行查看

读入数据点之后我们根据不同的 label 将数据点分为了红色和蓝色,并且画图展示出来了

# 从 data.txt 中读入点
with open('./data.txt', 'r') as f:
    data_list = [i.split('\\n')[0].split(',') for i in f.readlines()]
    data = [(float(i[0]), float(i[1]), float(i[2])) for i in data_list]

# 标准化
x0_max = max([i[0] for i in data])
x1_max = max([i[1] for i in data])
data = [(i[0]/x0_max, i[1]/x1_max, i[2]) for i in data]

x0 = list(filter(lambda x: x[-1] == 0.0, data)) # 选择第一类的点
x1 = list(filter(lambda x: x[-1] == 1.0, data)) # 选择第二类的点

plot_x0 = [i[0] for i in x0]
plot_y0 = [i[1] for i in x0]
plot_x1 = [i[0] for i in x1]
plot_y1 = [i[1] for i in x1]

plt.plot(plot_x0, plot_y0, 'ro', label='x_0')
plt.plot(plot_x1, plot_y1, 'bo', label='x_1')
plt.legend(loc='best')

在这里插入图片描述

定义Logistic 回归模型

class  LogisticRegression(nn.Module):
	def  __init__(self):
		super(LogisticRegression,  self).__init__()
		self.lr  =  nn.Linear(2,  1)
		self.sm  =  nn.Sigmoid()


	def  forward(self,  x):
		x  =  self.lr(x)
		x  =  self.sm(x)
		return  x

logistic_model  =  LogisticRegression()
if  torch.cuda.is_available():
	logistic_model.cuda()

criterion  =  nn.BCELoss()
optimizer  =  torch.optim.SGD(logistic_model.parameters(),  lr=1e-3,
momentum=0.9)

这里 nn.BCELoss 是二分类的损失函数,torch.optim.SGD 是随机梯度下降优化函数。然后训练模型,并且间隔一定的迭代次数输出结果。

训练模型 Training

for  epoch  in  range(50000):
	if  torch.cuda.is_available():
		x  =  Variable(x_data).cuda()
		y  =  Variable(y_data).cuda()
	else:
		x  =  Variable(x_data)
		y  =  Variable(y_data)
    #  ==================forward==================
    out  =  logistic_model(x)
    loss  =  criterion(out,  y)
    print_loss  =  loss.data
    mask  =  out.ge(0.5).float()
    correct  =  (mask  ==  y).sum()
    acc  =  correct.data[0]  /  x.size(0)
    #  ===================backward=================
    optimizer.zero_grad()

    loss.backward()
    optimizer.step()
	if  (epoch+1)  %  1000  ==  0:
        print('*'*10)
        print('epoch  {}'.format(epoch+1))
        print('loss  is  {:.4f}'.format(print_loss))
        print('acc  is  {:.4f}'.format(acc))

其中 mask=out.ge(0.5).float() 是判断输出结果如果大于 0.5 就等于 1,小于0.5 就等于 0,通过这个来计算模型分类的准确率。

因为数据相对简单,同时我们使用的是也是简单的线性 Logistic 回归,loss 已经降得相对较低,同时也有 91% 的准确率。

epoch  46000
loss  is  0.3116
acc  is  0.9100
**********
epoch  47000
loss  is  0.3098
acc  is  0.9100
**********
epoch  48000
loss  is  0.3080
acc  is  0.9100
**********
epoch  49000
loss  is  0.3063
acc  is  0.9100
**********
epoch  50000
loss  is  0.3046
acc  is  0.9100

拟合曲线 和 结果展示

w0,  w1  =  logistic_model.lr.weight[0]
w0  =  w0.data.cpu()
w1  =  w1.data.cpu()
b  =  logistic_model.lr.bias.data[0].cpu()
plot_x  =  np.arange(0.2,  1,  0.1)


plot_y  =  (-w0  *  plot_x  -  b)  /  w1
plt.plot(plot_x, plot_y, 'g', label='cutting line')
plt.plot(plot_x0, plot_y0, 'ro', label='x_0')
plt.plot(plot_x1, plot_y1, 'bo', label='x_1')
plt.legend(loc='best')

在这里插入图片描述

以上我们介绍了分类问题中的二分类问题和 Logistic 回归算法,一般来说,Logistic回归也可以处理多分类问题,但最常见的还是应用在处理二分类问题上,下一节会讲一下如何用神经网络解决非线性的分类问题

下一章传送门:Note12 多层神经网络

以上是关于Pytorh Note11 Logistic 回归模型的主要内容,如果未能解决你的问题,请参考以下文章

数学建模暑期集训11:逻辑回归(Logistic Regression)处理二分类问题

回归分析11:含定性因变量的回归模型

logistic回归模型的参数呈现线性关系

R语言glm拟合logistic回归模型:输出logistic回归的summary信息可视化logistic回归模型的系数logistic回归模型分类评估计算(混淆矩阵accuracy偏差)

probit回归与logistic回归有啥区别

logistic回归的介绍