逻辑回归
逻辑回归主要是解决分类问题
- 回归任务:结果是一个连续的实数
- 分类任务:结果是一个离散的值
分类任务不能直接使用回归去预测,比如在手写识别中(识别手写 0 − − 9 0 -- 9 0−−9),因为各个类别之间没有大小之差。
因此,对于分类问题,我们最终的输出是个概率,即属于某个类别的概率是多少,然后从概率集合里找最大值,作为当前预测的结果
下载MNIST
数据集
import torchvision
train_set = torchvision.dataset.MNIST(root="../dataset/mnist", train=True, download=True)
test_set = torchvision.dataset.MNIST(root="../dataset/mnist", train=False, dowload=True)
- 通过
train
参数来指定训练集和测试集
逻辑回归
将之前的学习时长—考试分数转化为二分类任务,即学习时长—是否通过考试
x(hours) | y(pass/fail) |
---|---|
1 | 0(fail) |
2 | 0(fail) |
3 | 1(pass) |
4 | ? |
其中, P ( y ^ = 1 ) + P ( y ^ = 0 ) = 1 P(\hat y = 1) + P(\hat y = 0) = 1 P(y^=1)+P(y^=0)=1
当输出的概率在 0.5 0.5 0.5附近时,即模型不确定,因此通常会输出一个不确定
的值
对于二分类任务,逻辑回归会先使用回归,生成一个得分值,即落在实数集区间内,然后再使用 s i g m o i d sigmoid sigmoid函数,将得分值映射到 [ 0 , 1 ] [0, 1] [0,1]区间内,得到预测概率
s i g m o i d sigmoid sigmoid函数
σ ( x ) = 1 1 + e − x \sigma (x) = \frac{1}{1+e^{-x}} σ(x)=1+e−x1
S i g m o i d Sigmoid Sigmoid常用来做二分类任务,常具备三个特征:
- 饱和函数
- 单调递增
- 有极限
当我们使用线性回归来得到逻辑回归的得分值时,逻辑回归模型的函数定义就如下所示:
y ^ = σ ( x ∗ ω + b ) \hat y = \sigma (x*\omega + b) y^=σ(x∗ω+b)
损失函数
线性回归使用的损失函数是计算预测值和真实值之差
而对于逻辑回归,由于我们得到的是概率,是一个 0 − 1 0-1 0−1分布,因此需要修改损失函数
l o s s = − ( y l o g y ^ + ( 1 − y ) l o g ( 1 − y ^ ) ) loss = -(ylog\hat y + (1-y)log(1-\hat y)) loss=−(ylogy^+(1−y)log(1−y^))
即我们比较的是分布之间的差异
交叉熵 c r o s s − e n t r o p y cross-entropy cross−entropy
存在两个分布 P D 1 ( x ) P_{D1}(x) PD1(x)和 P D 2 ( x ) P_{D2}(x) PD2(x)
两个分布的差异程度使用公式: ∑ i = 1 n P D 1 ( x i ) l n P D 2 ( x i ) \sum_{i=1}^{n}P_{D1}(x_i)lnP_{D2}(x_i) ∑i=1nPD1(xi)lnPD2(xi) 来衡量
上述公式越大时,两个分布的差异越小
模型的改变
模型构造的改变
class LogisticRegressionModel(torch.nn.Module):def __init__(self):super(LogisticRegressionModel, self).__init__()self.linear = torch.nn.Linear(1, 1)# 由于逻辑回归中Sigmoid函数不需要传参 所以在forward中直接计算即可# 在这里不需要实例化def forward(self, x):y_pred = F.sigmoid(self.linear(x))return y_pred
需要先将输入写入到linear()
线性模型中,再使用Sigmoid()
函数
模型损失函数的改变
使用交叉熵函数BCELoss
criterion = torch.nn.BCELoss(size_average=False)
整体代码
import torch
import matplotlib.pyplot as plt
import numpy as np########## 数据集准备 ##########
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[0], [0], [1]])########## 模型定义 ##########
class LogisticRegressionModel(torch.nn.Module):def __init__(self):super(LogisticRegressionModel, self).__init__()self.linear = torch.nn.Linear(1, 1)# 由于逻辑回归中Sigmoid函数不需要传参 所以在forward中直接计算即可# 在这里不需要实例化def forward(self, x):y_pred = torch.sigmoid(self.linear(x))return y_predmodel = LogisticRegressionModel()########## 损失函数和优化器的设置 ##########
criterion = torch.nn.BCELoss(size_average=False) # BCELoss -- 交叉熵函数
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)########## 模型训练 ##########
for epoch in range(1000):y_pred = model(x_data)loss = criterion(y_pred, y_data)print(epoch, loss.item())optimizer.zero_grad()loss.backward()optimizer.step()########## 模型测试 ##########
x = np.linspace(0, 10, 200)
x_test = torch.Tensor(x).view((200, 1)) # view()相当于reshape
y_test = model(x_test)
y = y_test.data.numpy() # 转化为np类型
plt.plot(x, y)
plt.plot([0, 10], [0.5, 0.5], 'r--')
plt.xlabel("Hours")
plt.ylabel("Probability of Pass")
plt.grid()
plt.show()