为什么我们需要了解Logistic regression逻辑回归?
因为神经网络的一个神经元就是Logistic regression逻辑回归。
Logistic regression(LR)逻辑回归是什么?
它就是套一个概率分布模型上去。什么是模型?模型就是一个函数比如:f(x)=ax+b。至于逻辑回归套的那个概率分布模型是什么稍后再说,先说套概率分布模型上去有什么用?假如需要判断样本x是属于A类还是属于B类。在前面提到了模型就是一个函数,概率分布模型就是输入一个样本数据x,函数输出它属于A类的概率。逻辑回归只能分出两种类。x属于A类的概率大于0.5那就我们可以认为当前样本属于A类,如果概率小于0.5那就认为它属于B类。
那么逻辑回归套的是什么函数呢?答:。其中是待求解的参数,不同的数据是不一样的。那我们怎么根据当前已有的数据调整得到最优的参数?答:用梯度下降。
如果你对梯度下降不理解可以参考这两篇文章:
易懂的神经网络理论到实践(1):单个神经元+随机梯度下降学习逻辑与规则
{高中生能看懂的}梯度下降是个啥?
pytorch编程实践
本文的实践会先介绍使用的数据是什么。然后介绍如何检验自己程序是否正确。然后介绍如何用pytorch的反向传播求导(求导结果是否正确可以我们自己手动计算下来检验),并用这个导数实现梯度下降。然后介绍如何我们自己求导实现梯度下降(我们自己写的导数是否计算正确检验方法1是可以用前面反向传播求导结果检验2是我们自己手动计算看程序运行结果是否正确)。
使用pytorch自带的自动求导工具求导,然后实现梯度下降
大家一定要注意机器学习必备下面那几个步骤。写程序一定要对这些步骤烂熟于心。
- 加载数据
- 输入样本计算模型的输出
- 计算损失函数对参数w的导数(梯度)
- 梯度下降调节参数w
- 重复2-4
1.加载数据
首先我们需要加载数据,这次我们想实现的是让逻辑回归识别逻辑异或(两个数字相同那就是0,两个数字不同那就是1)。
所以数据(前面两个数字)与标签(最后那个数字)是:
1 1 0
1 0 1
0 1 0
0 0 1
现在我们用代码实现加载数据
# -*- coding:utf-8 -*-
import torch
import numpy as np
'''
用逻辑回归实现异或功能
'''
# 加载数据
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
计算模型的输出
前面提到了逻辑回归的模型是。我们首先需要先初始化参数w。然后输入一个样本x,然后根据公式计算模型输出。接下来我们用代码实现它。很多同学不知道自己代码写的对不对,大家只需要自己算一下结果,然后看看程序输出是否符合自己计算结果。
# -*- coding:utf-8 -*-
import torch
import numpy as np
'''
用逻辑回归实现异或功能
'''
# 加载数据
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float, requires_grad=True)
# 加载一个数据,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 输出tensor(0.8808)
利用pytorch反向传播自动求导工具计算损失函数对参数w的导数
我们需要告诉pytorch损失函数,然后让它根据损失函数对参数w求导。接下来我们用代码实现。()
# -*- coding:utf-8 -*-
import torch
import numpy as np
'''
用逻辑回归实现异或功能
'''
# 加载数据
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float,requires_grad=True)
# 加载一个数据,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 输出tensor(0.8808)
loss = (f-label[i])**2
print(loss)# 输出:tensor([0.7758])
loss.backward() # 使用反向传播求损失函数对参数w的导数值
print(w.grad) # 损失函数对w的导数值tensor([0.1850, 0.1850])
利用反向传播的导数实现梯度下降
# -*- coding:utf-8 -*-
import torch
import numpy as np
'''
用逻辑回归实现异或功能
'''
# 加载数据
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float,requires_grad=True)
# 加载一个数据,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 输出tensor(0.8808)
loss = (f-label[i])**2
print(loss)# 输出:tensor([0.7758])
loss.backward() # 使用反向传播求损失函数对参数w的导数值
print(w.grad) # 损失函数对w的导数值tensor([0.1850, 0.1850])
learning_rate = 1e-2
w = w - learning_rate*w.grad
print('更新后的参数w',w)#更新后的参数w tensor([0.9982, 0.9982])
我们自己手动计算导数,并实现梯度下降
# -*- coding:utf-8 -*-
import torch
import numpy as np
'''
用逻辑回归实现异或功能
'''
# 加载数据
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float,requires_grad=True)
# 加载一个数据,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 输出tensor(0.8808)
#loss = (f-label[i])**2
# 计算损失函数loss对w的导数
# 我们把e^(-wx)这部分先存到一个变量里面
e_wx = torch.pow(np.e,-x.dot(w))
dloss_dw = 2*(f-label[i])*x*e_wx/(1+e_wx)**2
print(dloss_dw)
learning_rate = 1e-2
w = w - learning_rate*dloss_dw
print('更新后的参数w',w)#更新后的参数w tensor([0.9982, 0.9982])