逻辑斯蒂回归(刘二大人PyTorch第六讲)
上节的内容是回归,这节的内容是分类。
回归与分类的区别:
* 回归的目标是预测一个连续的数值。性输出的是一个具体的数值。可以使用均方误差(MSE)、平均绝对误差(MAE)等进行评估,通过最小化预测值与真实值
之间的距离优化模型。
* 分类的目标是将数据划分到不同的离散的类别中。输出是属于某个类别的概率。可以使用交叉熵损失函数(Cross-Entropy Loss)、0-1损失函数等进行评估,不同于回归的是,分类计算的是概率分布之间的差异。
- 数据准备
关于数据集:
torchvision库中自带MNIST数据集、CIFAR数据集,调用时使用torchvision.datasets.来调用。如下:
import torchvision
train_set = torchvision.datasets.MINIST(root='../dataset/mnist', train=True, download=True)
test_set = torchvision.datasets.MINIST(root='../dataset/mnist', train=False, download=True)
- 模型构建
不同于上一讲中线性模型的是,二分类问题需要将线性模型输出的具体数值转换为0-1之间的概率。即,我们需要找到一个函数(Sigmoid函数),能够把输出的实数映射到0-1之间。
显性地来看,二分类模型是在线性模型的输出后添加了Sigmoid函数。
二分类模型可以表示为:
Sigmoid函数调用方式:
import torch.nn.functional as F
F.sigmoid(...)
- 损失函数
分类任务输出的是分布,二分类输出的表示p(class=1),则
表示的是p(class=0)。
二分类任务常用的损失函数:二分类交叉熵损失函数:
优化器:SGD
import torch
criterion = torch.nn.BCELoss(size_average=False) #损失,实例化一个可调用的对象,需要输入的参数为(y_pred,y)
optimizer = torch.optim.SGD(model.parameters(),lr=0.01) # 使用随机梯度下降优化函数
- 训练单元
for epoch in range(1000):
optimizer.zero_grad() # 梯度清零
y_pred = model(x_data) #计算预测值,用于计算损失
loss = criterion(y_pred, y_data) #传入(y_pred,y_data),用于计算损失
loss.backward() # loss反向传播
optimizer.step() # 梯度更新
整体代码:
import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
# 1.准备数据
x_data = torch.Tensor([[1.0],[2.0],[3.0]])
y_data = torch.Tensor([[0],[0],[1]])
# 2.设计模型
class LogisticRegressionModel(torch.nn.Module):
def __init__(self):
super(LogisticRegressionModel,self).__init__()
self.linear = torch.nn.Linear(1,1)
def forward(self,x):
y_pred = F.sigmoid(self.linear(x))
return y_pred
# 模型实例化
model = LogisticRegressionModel()
# 3.设计损失(损失函数实例化),设计优化器
criterion = torch.nn.BCELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
# 4.训练
for epoch in range(1000):
optimizer.zero_grad() # 梯度清零
y_pred = model(x_data) # 计算预测值
loss = criterion(y_pred,y_data) # 计算损失
print(epoch, loss.item())
loss.backward() # loss反向传播
optimizer.step() # 梯度更新
# 测试
z= torch.Tensor([[4]])
print('z',model(z))
x = np.linspace(0,10,200) # 生成一个0-10之间均匀分布的包含200个点的一维numpy数组
x_t = torch.Tensor(x).view((200,1)) # 将numpy数组转换为PyTorch张量,并将其形状重塑为(200,1)
y_t = model(x_t) # 将重塑后的张量作为输入传递给model进行预测
y = y_t.data.numpy() # 从预测结果中提取数据,转换为numpy数组
plt.plot(x,y)
plt.plot([0,10],[0.5,0.5],c='r')
plt.xlabel('hours')
plt.ylabel('Probaility of Pass')
plt.grid()
plt.show()
输出结果:
0 2.375955820083618
1 2.3335862159729004
2 2.293276071548462
...
998 0.9634450078010559
999 0.9630558490753174
z tensor([[0.8957]], grad_fn=<SigmoidBackward0>)
Figure_1.png
Figure_1.png
补充:
关于.item()
和.data()
:
.data()
用于获取张量的数据部分,同时将其从计算图中分离出来,后续对这个数据进行的操作不会影响原张量的梯度计算。适用于不需要跟踪梯度的场景下使用,如推理阶段,只关心模型的输出结果而不需要计算梯度,使用 .data
可以避免不必要的梯度计算,提高效率。不过在新的 PyTorch 版本中,更推荐使用 .detach()
方法,因为 .data
在一些复杂的梯度计算场景下可能会引发意外问题。返回值是一个新的张量,其数据与原张量相同,但没有梯度信息。
.item()
用于从包含一个元素的张量中提取该元素的值,并将其转换为Python的基本数据类型(如‘float’或‘int’)。返回的是 Python 的基本数据类型,如 float
或 int
,不再是张量对象,不能再进行张量操作,只能进行 Python 原生的数学运算等操作。