利用pytorch和交叉熵损失函数原理完成Iris分类器构造
一 .基于对逻辑回归的数学基础
- 从分类开始谈起
某个样本属于A类还是B类,从结果上讲就是值为0,还是值为1。但影响这个分类的是由一些因素决定的。我们从数学角度可以使用向量表示这些因素(这些因素就影响某个样本属于A类还是B类):
其中就是表示一个样本,样本
具有n个影响分类的特征。如果考虑偏置项,则可以增加一个份量1。
- 建立分类的逻辑模型
我们假设有两套标准判定样本所属的分类,使用数学函数表示如下:
|-样本x属于A的可能性;
|-样本x属于B的可能性;
这样我们就可以建立一个分类模型:
当,则样本
属于A类;当
,则样本
属于B类;
可以把上述模型表示为:
- 分类逻辑模型的概率分析基础
如果假设与
是线性关系,同时考虑
的误差都独立服从正态分布,可以把
表示如下:
|-
|-
其中是服从独立分布的误差项,可以假设服从正态分布。
记,则:
|-
从而分类逻辑模型可以表示如下:
|-
其中
则样本X属于A的概率可以表示为:
|-
从正态分布可以继续推导:
|-
其中是变量
的累积分布函数;
表示样本属于A的概率
- probit模型
上述推导的公式在学术上称为probit模型,建立的回归模型也称proit回归。
是正态分布函数的累积函数,上述累积分布函数,在服从正态分布的时候比较麻烦,因为正态分布的累积函数还没有解析表达式能够表达。 从而其参数估计非常麻烦,如果需要应用,则需要简化( 做近似处理 )。
为了解决正态分布累积函数的问题,正态分布的累积函数的计算居然是通过查表的形式提供运算结果,大家如果想不起,可以查阅自己的高中数据或者大学数学书。 - 正态分布的近似处理
正态分布表示:
其中:μ表示期望(均数),σ表示标准差,σ2表示方差
记正态分布为,标准正态分布是
我们可以简化下正态分布累积函数的表示:
因为是线性,所以只需要考虑标准正态分布。
在数学上存在一个逻辑分布,与正态分布非常相似, - 逻辑分布与标准正态分布
下面使用可视化来认识下逻辑分布函数与正态分布函数的近似度。
|- 正态分布:
|- 逻辑分布:
逻辑分布函数与正态分布的区别就在于:逻辑分布有累积函数,其累积函数如下:
|- 逻辑分布累积函数:
下面是逻辑分布函数,正态分布函数的比较:
% matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
# 绘图的坐标轴
figure=plt.figure('正态分布与逻辑分布', figsize=(10, 4))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8], label='逻辑分布与正态分布')
ax.set_xlabel('x值')
ax.set_ylabel('y值')
# 设置绘制曲线范围
ax.set_xlim(left=-10,right=10) # x取值范围
ax.set_ylim(bottom=0, top=0.5) # 概率在[0, 1) 之间
# 标准正态分布函数--------------------
# x取值范围
x_n=np.linspace( -10 ,10, 100, dtype=np.float32 )
# 系数-方差
sigma=1
# 系数-均值
mu=0
# 正态分布常数系数
coefficient = 1.0 / ( np.sqrt( 2 * np.pi) * sigma )
# 正态分布指数
exponent = -(x_n-mu)**2/(2*sigma**2)
y_n=coefficient * np.exp( exponent )
ax.plot(x_n, y_n,color='r',label='正态分布')
# 逻辑分布函数--------------------
x_l=np.linspace( -10 ,10, 100, dtype=np.float32 )
y_l=np.exp( -x_l ) / ( 1 + np.exp( -x_l ) )**2
ax.plot(x_l, y_l,color='b',label='逻辑分布')
ax.legend()
figure.show(warn=False)- 逻辑分布与标准正态分布的累积函数
标准正态分布没有累积函数,所以我们采用scipy的积分函数来绘制。
使用积分表示正态分布累积函数的公式如下:
|-,
% matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import scipy.integrate as integrate
# 定义正态函数,用于积分运算
def normal(t,m,s):
# 系数-方差
sigma=s
# 系数-均值
mu=m
# 正态分布常数系数
coefficient = 1.0 / ( np.sqrt( 2 * np.pi) * sigma )
# 正态分布指数
exponent = -(t-mu)**2/(2*sigma**2)
re=coefficient * np.exp( exponent )
return re
def cumulative(x):
re=integrate.quad(
normal, # 积分函数
-np.inf, # 积分下限
x, # 积分上限
args=(0.0, 1.0) # 传递给函数的参数(除第一个参数外,按照顺序来)
)
return re[0] #第一个是积分,第二个是误差上限
# 绘图的坐标轴
figure=plt.figure('正态分布与逻辑分布', figsize=(10, 4))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8], label='逻辑分布与正态分布')
ax.set_xlabel('x值')
ax.set_ylabel('y值')
# 设置绘制曲线范围
ax.set_xlim(left=-10,right=10) # x取值范围
ax.set_ylim(bottom=-0.1, top=1.1) # 概率在[0, 1) 之间
# 标准正态分布函数--------------------
# x取值范围
x_n=np.linspace( -10 ,10, 100, dtype=np.float32 )
y_n=[cumulative(x) for x in x_n ]
ax.plot(x_n, y_n,color='r',label='正态分布累积函数')
# 逻辑分布函数--------------------
x_l=np.linspace( -10 ,10, 100, dtype=np.float32 )
y_l=1.0 / ( 1 + np.exp( -x_l ) )
ax.plot(x_l, y_l,color='b',label='逻辑分布累积函数')
ax.legend()
ax.grid(b=True)
figure.show(warn=False)- 最佳的逻辑分布
如果逻辑分布参数做一些调整,可以最佳接近。下面是最佳逻辑分布累积函数表示:
|-
下面是可视化后的直观效果。
% matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import scipy.integrate as integrate
# 定义正态函数,用于积分运算
def normal(t,m,s):
# 系数-方差
sigma=s
# 系数-均值
mu=m
# 正态分布常数系数
coefficient = 1.0 / ( np.sqrt( 2 * np.pi) * sigma )
# 正态分布指数
exponent = -(t-mu)**2/(2*sigma**2)
re=coefficient * np.exp( exponent )
return re
def cumulative(x):
re=integrate.quad(
normal, # 积分函数
-np.inf, # 积分下限
x, # 积分上限
args=(0.0, 1.0) # 传递给函数的参数(除第一个参数外,按照顺序来)
)
return re[0] #第一个是积分,第二个是误差上限
# 绘图的坐标轴
figure=plt.figure('正态分布与逻辑分布', figsize=(10, 4))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8], label='逻辑分布与正态分布')
ax.set_xlabel('x值')
ax.set_ylabel('y值')
# 设置绘制曲线范围
ax.set_xlim(left=-10,right=10) # x取值范围
ax.set_ylim(bottom=-0.1, top=1.1) # 概率在[0, 1) 之间
# 标准正态分布函数--------------------
# x取值范围
x_n=np.linspace( -10 ,10, 100, dtype=np.float32 )
y_n=[cumulative(x) for x in x_n ]
ax.plot(x_n, y_n,color='r',label='正态分布累积函数 $F_{\epsilon}(x)=\int_{-\infty}^{x}\dfrac{1}{\sqrt{2\pi}\sigma}exp(-\dfrac{(t-\mu)^2}{2\sigma^2})\mathrm{d} t$')
# 逻辑分布函数--------------------
x_l=np.linspace( -10 ,10, 100, dtype=np.float32 )
y_l=1.0 / ( 1 + np.exp( -1.702*x_l ) )
ax.plot(x_l, y_l,color='b',label='逻辑分布累积函数 $S(x)=\dfrac{1}{1+e^{-1.702x}}$ ')
ax.legend()
ax.grid(b=True)
figure.show(warn=False)9.sigmoid函数
就是鼎鼎大名的sigmoid函数,该函数具备许多良好的性质。尤其是深度学习中的大杀器!经常会用到。
函数的特点:
|- 函数的导数可以用自身表示:
|- 连续处处可微
|- 值在[0,1)范围
|- 单调递增
|- 非线性
|- 平滑性
|- 原点附近近似identity(f(x)≈x)或者先线性性。
函数的缺点:
|- 运算量大(后面使用梯度下降算法可以提现出来,尤其误差传递的时候)
|- 容易出现梯度消失的情况,从而不利于样本训练,甚至完不成梯度训练。(大家可以从逻辑分布函数看得出来,sigmoid函数的导数就是逻辑分布函数,逻辑分布函数从0开始,就逐步趋向于0,容易产生梯度消失)
二. 利用pytorch和numpy模块对数据集进行处理
模型
- 预测:
- 最好
就是是下面损失函数最小的
- 损失函数:交叉熵函数
实现
- 加载数据集
- 定义学习的w, b
循环
- 计算预测值
- 使用交叉熵计算损失值
- 求导数
- 更新w,b
from sklearn.datasets import load_iris
import numpy
import torch
# 加载数据集
data, target = load_iris(return_X_y=True)
# x = torch.from_numpy(data[0:100]).float()
x = torch.Tensor(data[:100]) # FloatTensor = Tensor
y = torch.Tensor(target[:100]).view(100, 1)
# 定义学习参数
w = torch.randn(1, 4)
b = torch.randn(1)
w.requires_grad= True
b.requires_grad= True
# 超参数
epoch = 500000
lr = 0.0001
for n in range(epoch):
# 预测
# y_ = w @ x.T + b
y_ = torch.nn.functional.linear(x, weight=w, bias=b)
y_ = torch.sigmoid(y_)
# 计算损失
loss = torch.nn.functional.binary_cross_entropy(y_, y)
# 求导
loss.backward()
# 更新
with torch.no_grad():
w -= lr * w.grad
b -= lr * b.grad
# 清空导数
w.grad.zero_()
b.grad.zero_()
y_[ y_ > 0.5] = 1
y_[ y_ <= 0.5] = 0
corr_rate = (y == y_).float().mean()
if n % 100 ==0:
print(f"损失值:{loss:8.6f}, 正确率:{corr_rate * 100: 8.2f}")结果如下


















