PyTorch深度学习实践——6.逻辑sigmoid函数
PyTorch深度学习实践——6.逻辑sigmoid函数
课程链接: 《PyTorch深度学习实践》6.逻辑斯蒂回归
虽然叫回归,但是是做分类的
线性回归模型
单样本损失
在线性空间,我们的估计值y属于一个连续的空间,这种任务叫做回归任务,但是在很多的机器学习任务中,我们要做的是分类
比如ministr数据集,训练集60000个,测试集10000个,有10个分类,我们模型估算出来的结果是一个0…9离散值的集合,我们要估算的是y属于哪一个,这种问题叫做分类问题
然而我们并不是输出输入的样本所属的类别,而是输出它属于每个类别的概率,概率最大的一项作为我们分类的结果
这些都叫sigmoid函数,满足函数值有极限,函数值在(-1,1)之间,都是单调增函数,都是饱和函数,满足这几个条件就叫sigmoid函数,在所有的sigmoid函数中逻辑斯蒂函数最出名,所以现在有些框架里面就直接把逻辑斯蒂函数叫做sigmoid函数,在pytorch里面逻辑斯蒂函数就叫做sigmoid函数
逻辑斯蒂回归是做分类用的,输出是概率的分布,
回归与分类的区别:
分类输出y_hat可以是通过的概率(【0,1】),也可以是结果,通过或挂科。
分类输出为概率,在训练时,logistic要把输出值从是实数空间映射到【0,1】
Logstic回归模型:
论文中常把logistic函数写成\sigma(x)
损失函数:
线性回归模型中loss=(y_hat-y)**2在几何上表示两点距离差异
logistic回归模型中,输出是概率的分别,loss要比较概率之间的分布差异,(KL散度,cross-entrpoy交叉熵)
交叉熵举例:
比较D分布和T分布差异性的大小,越大越好
BCE二分类损失函数如上
y是样本真实值,y_hat是预测值,y=1时22,y_hat趋近于一则损失越小,否则越大
mini-batch loss 把BCE加起来求均值即可
linear函数与线性回归函数相同,因此code也相同,因为\sigma里没有参数,也不需要更新,直接在linear后加一个sigmod,最前面加一份functional即可
损失不同:从原来的MSE编程BCE(binary cross entropy)
思路:
1、准备数据
2、模型构造
3、损失和优化器
4、循环训练
5、投入模型数据,计算结果
import torch
import torch.nn.functional as F # 函数包
import numpy as np
import matplotlib.pyplot as plt
# x,y各有三个数据,每一个数据都只有一个特征,形式为3行一列
x_data = torch.Tensor([[1.0], [2.0], [3.0]]) #构建数据集
#注意括号的形式
y_data = torch.Tensor([[0], [0], [1]]) # 分类数据
class LogisticRegressionModel(torch.nn.Module): #括号里面表示继承类
# 初始化函数和线性回归模型的一样,因为logistic函数中没有新的参数需要初始化
def __init__(self): # 构造函数与线性模型一样,无其他参数
#构造函数
super(LogisticRegressionModel, self).__init__()
self.linear = torch.nn.Linear(1, 1)
#torch.nn.Linear是pyTorch里面的一个类,加了括号就是实例化对象,包含了权重和偏置两个张量
#可以直接用Linear完成 权重*输入+偏置的计算
#Linear也是继承自Module,所以可以自动进行反向传播
#nn:Neural Network神经网络
#linear是由Linear实例化得到的
# (1,1)代表的是输入和输出的特征维度都是一维
# 该层需要学习的参数是w和b,且方式为linear.weight()和linear.bias()
def forward(self, x):
y_pred = F.sigmoid(self.linear(x)) # F.sigmoid()
return y_pred
#构造函数用于初始化对象, forward是前馈过程中需要执行的计算,没有backward,这是因为Module构造的对象会根据你的计算图自动实现backward
model = LogisticRegressionModel() #创建一个LogisticRegressioMoel类的实
#用模型的时候这样调用,也可以传入参数x,x就送入forward函数,计算出y_pred
criterion = torch.nn.BCELoss(size_average=False) # 用BCE损失函数:cross-entropy(交叉熵),不需要求均值
#构造损失函数
#MSELoss需要有y,y_pred,然后构造计算,用MSELoss的共识算出来是一个向量,再把向量求和,最后得出标量的损失值
#MSELoss的计算过程也要构建计算图,只要是需要构建计算图,就应该是继承自Module,MSELoss继承自nn.Module
#size_average=False表示得到的损失不求均值
#优化器
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
#BCELoss类参数:size_average=True/False是否求均值、reduction=True/False是否降维
# model.parameter 自动完成参数的初始化操作
#优化器不会构建计算图 torch.optim.SGD是一个类,带了参数就是实例化了这个类
#model.parameters()会检查model里面所有的成员,如果成员里面有相应的权重,就把这些都加到最后训练的参数集合上
#lr是学习率,当模型比较复杂,pyTorch还支持对模型的不同部分使用不同的学习率,w=w-lr*(损失对权重的导数)
#训练过程
for epoch in range(1000):
y_pred = model(x_data) #先在前馈里面算出y_pred
loss = criterion(y_pred, y_data) #算损失
# 结合预测值和真实值,最后输出损失值
print(epoch, loss.item()) #loss是一个对象是标量,打印的时候会自动调用__str__(),不会产生计算图
optimizer.zero_grad() # 在反向传播之前一定要释放梯
#进行训练的时候梯度归零
loss.backward() # 反向传播Autograd
optimizer.step() # update
#更新,step函数用于更新,会根据所有参数里面所包含的梯度以及预先设置的学习率进行更新
x = np.linspace(0, 10, 200) #0-10之间平均取200个点
# 返回0-10等间距的200个数
x_t = torch.Tensor(x).view((200, 1)) # .view() 转换成矩阵
# reshape成一个200行1列的矩阵tensor
#类似于np的reshape
y_t = model(x_t) # 将张量送到训练好的模型中,计算结果
#进行测试
# 传入模型进行测试
y = y_t.data.numpy() # 调用numpy将y_t变成n维数组
plt.plot(x, y)
# 图2——这是y=0.5那条横线
plt.plot([0, 10], [0.5, 0.5], c='r') # 画出y=0.5时的分界线
plt.xlabel('Hours')
plt.ylabel('Probability of Pass')
plt.grid() # x和y轴的网格线
plt.show()
输出结果:
Epoch = 0 Loss = 2.6060
Epoch = 100 Loss = 1.9397
Epoch = 200 Loss = 1.7697
Epoch = 300 Loss = 1.6271
Epoch = 400 Loss = 1.5065
Epoch = 500 Loss = 1.4037
Epoch = 600 Loss = 1.3155
Epoch = 700 Loss = 1.2390
Epoch = 800 Loss = 1.1721
Epoch = 900 Loss = 1.1133
结论:
可以看到大约在2.5小时左右分为两类:
1、小于2.5小时时,结果为0,意为不通过;
2、大于2.5小时时,结果为1,意为通过考试。
torchversion数据集
# mnist数据集,手写数字识别
mnist_train_set = torchvision.datasets.MNIST(root='./dataset/mnist', train=True, download=False)
mnist_test_set = torchvision.datasets.MNIST(root='./dataset/mnist', train=False, download=False)
# CIFAR-10数据集——飞机、卡车、猫、鸟等
cifar10_train_set = torchvision.datasets.CIFAR10(root='./dataset/cifar10', train=True, download=True)
cifar10_test_set = torchvision.datasets.CIFAR10(root='./dataset/cifar10', train=False, download=True)
- logistic 函数
(也可以叫sigmoid函数,logistic函数是最典型的sigmoid函数)
将变量映射到0-1之间的数
问题描述:根据输入的学习时间,来预测考试是否合格,最终输出是考试通过的概率。(是一个二分类问题)
概率值用logistic函数值来表示,函数中输入的x是原来的y_pred。
logistic函数图像如图所示,饱和函数—— 导数图像服从正态分布。
sigmoid函数
特点(充分条件)
饱和函数
单调增
有极限
-
数据集的改变:因为是二分类问题,y 的取值只能是0或1;
-
损失函数的改变:不再使用MSE损失函数,改为使用BCE损失函数,由于PyTorch版本更新,将
size_average=False 更改为 reduction='sum'
-
def __init__没有改变:原因是,\delta (x)(逻辑斯蒂回归函数)是一个没有参数的函数,不需要在构造函数中进行初始化,直接调用就可以;
-
模型的改变:由于PyTorch版本更新,不用再导入torch.nn.functional包,可以直接使用包中的Sigmoid函数进行训练,如下图;
实现线性回归
import torch
# Pytorch实现线性回归
# x,y是矩阵,3行1列 也就是说总共有3个数据,每个数据只有1个特征。
x_data = torch.Tensor([[1.0],[2.0],[3.0]])
y_data = torch.Tensor([[2.0],[4.0],[6.0]])
# Module实现了函数__call__(),call()里面有一条语句是要调用forward()。
# 所以需要重写forward()覆盖掉父类中的forward()。
class LinearModel(torch.nn.Module):
def __init__(self):
super(LinearModel, self).__init__()
# (1,1)是指输入x和输出y的特征维度,这里数据集中的x和y的特征都是1维的。
self.linear = torch.nn.Linear(1,1)
def forward(self,x):
y_pred = self.linear(x)
return y_pred
model = LinearModel()
criterion = torch.nn.MSELoss(size_average=False) # 不计算平均值。
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
for epoch in range(1000):
# forward体现是通过以下语句实现的。
y_pred = model(x_data)
loss = criterion(y_pred,y_data)
print('progress : ',epoch,loss.item())
optimizer.zero_grad()
loss.backward() # 反向传播,计算梯度
optimizer.step() # 更新w和b的值
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.data)
逻辑斯蒂回归
# 逻辑斯蒂回归
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn.functional as F
# 1. Prepare Dataset
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[0], [0], [1]])
# 2. Define Model
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. Construct Loss and Optimizer
# 默认情况下,loss会基于element平均,如果size_average=False的话,loss会被累加.
criterion = torch.nn.BCELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
# 4. Training Cycle
for epoch in range(100):
y_pred = model(x_data)
loss = criterion(y_pred,y_data)
print('progress:', epoch, loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
x = np.linspace(0,10,200) # 0-10之间取200个点。
x_t = torch.Tensor(x).view((200,1)) # 维度变换
y_t = model(x_t)
y = y_t.data.numpy()
plt.plot(x,y)
# plt.plot([0.10],[0.5,0.5],c='r')
plt.xlabel('Hours')
plt.ylabel('Probability of Pass')
plt.grid() # 显示网格线 1=True=默认显示;0=False=不显示
plt.show()
2301_81315324: 那个如果要控制混杂,建立多个模型,是不是要用分层cox回归呀!!求大佬解答
Cathyma0321: 讲得真清楚啊,简洁明了
m0_70042178: 变量已经是数值了还是出现了这个错误咋整呀
weixin_52072060: 网状META
m0_65472795: 请问是哪个公众号呀?