说是回归,实际是在讨论分类问题。
如下的分类图,里面含有0-9 十个数字。
这时候就不能再使用前面几节学过的线性回归模型(y = w * x + b)了,因为图片中的数字并没有对应到实际抽象的数字,我们只做分类,图片类别之间是没有大小的。
也就是我们要算出来 根据输入值,算出其属于某一部分的概率。
例如之前在线性回归中使用的数据模型:
x表示学习几个小时,y表示考试中可以得到几分。
而现在的数据模型改为:
x依旧是学习几个小时,y变为是否能够通过考试,0不通过,1通过。 此时为明显的分类问题,此处叫二分类问题。
我们需要计算的y(预)为 通过或者不通过的概率。且仅需要计算一个值,毕竟只有两种情况嘛…
将所得到的结果映射到图像上,因为是概率值,所以 y的取值范围是0-1.
使用映射函数:
则模型更新为:
添加这个变换主要作用就是将结果值映射到0-1之间。
流程图:
对比线性回归只多了一个用于映射的饱和函数。
图像为:
显然 x趋于正无穷时,y趋于1.
x趋于负无穷时,趋于0.
x = 0时 y=0.5
这种函数叫做 饱和函数。
其他各种饱和函数:
可以将结果映射到-1 -到 1 之间。
饱和函数都有极限,都是单调增函数。
损失函数的变化:
二分类的损失函数叫 BCE
之前的损失函数计算的是两个实数值直接的差。
而现在输出的是类别为 “通过” 的概率值 即y(预)。所以 1-y(预)就是 “不通过” 类别的概率 。
此时要分清,真实值y只有0和1. 预测值y表示的是当前y为1(即表示通过)的概率。
显然如果真实值 y=0 则说明 未通过。也就是 分类为 "通过"计算出来的结果为0.即0%概率。 反之 1-y 就是表示分类为“未通过”的概率是1,即100%概率。
所以是比较分布之间的差异。
假设有两个样本数据分布。
计算 公式,,即交叉熵。
之前的损失函数叫MSE 现在的叫BCE。
由损失函数公式 BCE可以看出。y(预)越接近y ,所得到的损失函数BCE越小。
和线性回归代码比较:
在编辑代码时发现 F.sigmoid 现版本中已经改为 torch.sigmoid。也就是不需要导入 torch.nn.functional 了 直接import torch 然后用torch.sigmoid
原: y_pre = F.sigmoid(self.linear(x))
现: y_pre = torch.sigmoid(self.linear(x))
通过开始的那个算法流程图的比较也可以看出来。和线性回归基本没差,就是多了一个函数映射的变化。所以在求y(预)的那行代码,先求之前线性模型里的值,然后sigmoid函数映射一下。
损失函数再改变一下 之前用MSE,现在用BCE。
数据准备上的变化:
之前是两组实数,
现在的y表示分类 ,只有两类。0表示未通过,1表示通过。
其余位置没有变化。
然后进行绘图:
linspace()函数:
numpy.linspace(start, stop, num=50) (开始值,结束值,在区间均匀的分割成多少个)
Tensor.view()函数:
torch.Tensor(x).view((行数,列数)) 相当于numpy里面的reshape()方法。
data.numpy()函数:
读取张量中的值,变成数组。
完整代码
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 LogistRegressionMode(torch.nn.Module):
def __init__(self):
super(LogistRegressionMode, self).__init__()
self.linear = torch.nn.Linear(1, 1)
def forward(self,x):
y_pre = torch.sigmoid(self.linear(x))
return y_pre
model = LogistRegressionMode()
# 损失函数
criterion = torch.nn.BCELoss(reduction='sum')
# 优化器
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
w_ll = []
loss_ll = []
# 循环训练
for i in range(1000):
y_pre = model(x_data) # 拿预测值
loss = criterion(y_pre, y_data) # 拿损失函数
loss_ll.append(loss.item())
optimizer.zero_grad() # 梯度清零
loss.backward() # 反向传播
optimizer.step() # 更新权重值
w_ll.append(model.linear.weight.item())
print("这里是权重值W",w_ll)
print("这里是损失函数loss",loss_ll)
# 模型训练测试
x = np.linspace(0,10,200) # 从0到10分为均匀的200块
x_d = torch.Tensor(x).view(200,1) # 将数据变成200行1列的张量
y_pre = model(x_d) # 拿去训练得到y的预测值
y = y_pre.data.numpy() # 从得到的y预测值张量 变成数组数据
# 绘图
plt.rcParams['font.sans-serif'] = ['KaiTi']
plt.plot(x,y)
plt.plot([0,10],[0.5,0.5],color='red') # 绘制中间的红线 后面的参数也可以直接写成 c = 'r'
plt.xlabel("学习的小时数")
plt.ylabel("通过的概率")
plt.grid() # 添加网格
plt.show()
结果: