Pytorch深度学习之Logistic回归
刘二大人Pytorch深度学习入门笔记及代码实现
前言
本系列文章作为自己深度学习入门的记录,该系列笔记参考刘二大人Pytorch深度学习实践课程实现,包括笔记与心得,一方面督促自己完成相关计划,另一方面有规律的记录加深自己对深度学习相关内容的理解。
提示:以下是本篇文章正文内容,下面案例可供参考
一、为什么提出逻辑斯蒂回归?
1、对于分类问题,模型经过训练,希望得到的结果是我们的输入到底属于哪一类,而对于线性回归,一般是在二维平面下估计输入x对应的输出y值。 正如下图所示:x | y |
---|---|
1 | 2 |
2 | 4 |
3 | 6 |
4 | ? |
线性回归希望得到一个表达式:
y
=
w
∗
x
+
b
y = w * x + b
y=w∗x+b训练得到
w
、
b
w、b
w、b的具体值。利用该式子可以对不同输入估算输出的值。分类问题不在追求y的具体数值为多少,更加希望得到一个关于输出
y
^
\hat y
y^的分布。分类问题,我们不能让模型训练的结果简单的输出
y
=
0
,
1
,
2
,
3
,
.
.
.
y = 0,1,2,3,...
y=0,1,2,3,...原因很简单,分类问题不再属于线性问题,输入相似不代表输出就临近。以手写数字识别为例,7、9这两个数字输入很相似(形状相似)但是按照线性回归得到的表达式,各自对应的输出结果不会很相近,因为同一个模型下,输入8得到的结果和7、9更加接近。
这时我们可以知道分类问题的核心:根据不同的输入,得到对应不同输出(即分类类别)的概率分布,原来的求值变为求概率。
P
(
y
^
=
i
)
=
p
i
P(\hat y = i) = p_i
P(y^=i)=pi
∑
p
i
=
1
\sum p_i = 1
∑pi=1
我们需要找到一个函数能够实现输出从具体值向概率分布的转变,有这样一类函数他们满足:
- 单调递增
- 有极限
- 是饱和函数
- 导数形状与正态分布相似
这一类函数称为Sigimod函数(激活函数)他可以把一个值从实数域映射到 y ∈ [ 0 , 1 ] y \in [0,1] y∈[0,1]最常用的激活函数为Logistic函数:
Δ ( x ) = 1 1 + e − x \Delta(x) =\cfrac{1}{1 + e^-x} Δ(x)=1+e−x1
函数图像为:
这样在前馈网络中仅对输出进行变换就实现了从线性回归到分类问题的转变。
二、损失函数的选择
1.由于输出从原来的具体值变为概率分布,原有的MSE损失函数不在可取,因为模型得到的值限定在[0,1]之间,还是相减取平均的话得到的损失值很小,不利于模型参数的更新。
2.从构建损失函数的目的出发,我们希望利用这个式子反应模型训练值与真实值之间的差异,经过多次迭代训练,是的损失值趋近全局最小值。而每次训练损失函数值的变化决定的梯度下降的方向。
3.经过以上分析后我们选择交叉熵损失函数。
criterion = torch.nn.BCELoss(size_average=False)
三、代码实现
4.对于一个数据集:
x | y |
---|---|
1 | 0 |
2 | 0 |
3 | 1 |
4 | ? |
利用深度学习框架实现二分类问题,代码如下:
import torch
import torch.nn.functional as F
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[0], [0], [1]])
class LinearModel(torch.nn.Module):
def __init__(self):
super(LinearModel, self).__init__()
self.linear = torch.nn.Linear(1, 1)
def forward(self, x):
y_pred = F.sigmoid(self.linear(x))
return y_pred
model = LinearModel()
#这个过程是构建计算图
criterion = torch.nn.BCELoss(size_average=False)
#对优化器进行类的实例化,不会构建计算图
optimizer = torch.optim.SGD(model.parameters(), lr= 0.01)
#进行训练
for ecoph in range(1000):
#进行前馈 model是实例化的模型类,是callable的对他进行传参数,直接可以调用进行计算
y_pred = model(x_data)
#计算实际损失
loss = criterion(y_pred, y_data)
print(ecoph ,loss.item())
#一定要进行梯度清零,计算一次损失后就会相应计算梯度,如果不清零就会将梯度累加,导致参数更新出现问题
optimizer.zero_grad()
#进行反馈更新参数
loss.backward()
optimizer.step()
print("w= ", model.linear.weight.item())
print("b= ", model.linear.bias.item())
x_test = torch.Tensor([4.0])
y_test = model(x_test)
print("y_pred =", y_test.item())
代码得到结果: