利用pytorch和交叉熵损失函数原理完成Iris分类器构造

利用pytorch和交叉熵损失函数原理完成Iris分类器构造

一 .基于对逻辑回归的数学基础

  1. 从分类开始谈起
      某个样本属于A类还是B类,从结果上讲就是值为0,还是值为1。但影响这个分类的是由一些因素决定的。我们从数学角度可以使用向量表示这些因素(这些因素就影响某个样本属于A类还是B类):
      
       x = ( x 1 , x 2 , … , x n ) x=(x_1,x_2,\dots,x_n) x=(x1,x2,,xn)
      其中 x x x就是表示一个样本,样本 x x x具有n个影响分类的特征。如果考虑偏置项,则可以增加一个份量1。
       x = ( x 1 , x 2 , … , x n , 1 ) x=(x_1,x_2,\dots,x_n,1) x=(x1,x2,,xn,1)

  2. 建立分类的逻辑模型
      我们假设有两套标准判定样本所属的分类,使用数学函数表示如下:
        |-  y A = f ( x ) y_A=f(x) yA=f(x)  样本x属于A的可能性;
        |-  y B = g ( x ) y_B=g(x) yB=g(x)  样本x属于B的可能性;
      
      这样我们就可以建立一个分类模型:
      
       y = { 1 , y A > y B 0 , y A ⩽ y B y=\begin{cases} 1,\quad y_A>y_B\\ 0,\quad y_A\leqslant y_B\\ \end{cases} y={1,yA>yB0,yAyB
      
      当 y = 1 y=1 y=1,则样本 x x x属于A类;当 y = 0 y=0 y=0,则样本 x x x属于B类;
      
      可以把上述模型表示为:
      
       y = { 1 , y A − y B > 0 0 , 其 他 y=\begin{cases} 1,\quad y_A-y_B>0\\ 0,\quad 其他\\ \end{cases} y={1,yAyB>00,

  3. 分类逻辑模型的概率分析基础
      
       如果假设 y A , y B y_A,y_B yA,yB x x x是线性关系,同时考虑 y A , y B y_A,y_B yA,yB的误差都独立服从正态分布,可以把 y A , y B y_A,y_B yA,yB表示如下:
      
      |- y A = x W A + ϵ A y_A=xW_A+\epsilon_A yA=xWA+ϵA
      |- y B = x W B + ϵ B y_B=xW_B+\epsilon_B yB=xWB+ϵB
      
      其中 ϵ A , ϵ B \epsilon_A,\epsilon_B ϵA,ϵB是服从独立分布的误差项,可以假设服从正态分布。
      记 z = y A − y B z=y_A-y_B z=yAyB,则:
      |- z = x ( W A − W B ) + ( ϵ A − ϵ B ) z=x(W_A-W_B)+(\epsilon_A-\epsilon_B) z=x(WAWB)+(ϵAϵB)
      
      从而分类逻辑模型可以表示如下:
      |- y = { 1 , z > 0 0 , 其 他 y=\begin{cases} 1,\quad z>0\\ 0,\quad 其他\\ \end{cases} y={1,z>00,
      其中 W = W A − W B , ϵ = ϵ A − ϵ B W=W_A-W_B,\epsilon=\epsilon_A-\epsilon_B W=WAWB,ϵ=ϵAϵB
       z = x W + ϵ z=xW+\epsilon z=xW+ϵ
      
      则样本X属于A的概率可以表示为:
      |- P ( y = 1 ) = P ( z > 0 ) = P ( x W + ϵ > 0 ) = P ( ϵ > − x W ) P(y=1)=P(z>0)=P(xW+\epsilon>0)=P(\epsilon>-xW) P(y=1)=P(z>0)=P(xW+ϵ>0)=P(ϵ>xW)
      从正态分布可以继续推导:
      |- P ( y = 1 ) = 1 − P ( ϵ ⩽ − x W ) = 1 − F ϵ ( − x W ) P(y=1)=1-P(\epsilon\leqslant-xW)=1-F_{\epsilon}(-xW) P(y=1)=1P(ϵxW)=1Fϵ(xW)
      其中 F ϵ F_{\epsilon} Fϵ是变量 ϵ \epsilon ϵ的累积分布函数; P ( y = 1 ) P(y=1) P(y=1)表示样本属于A的概率

  4. probit模型
      上述推导的公式在学术上称为probit模型,建立的回归模型也称proit回归。
      
       P ( y = 1 ) = 1 − F ϵ ( − x W ) P(y=1)=1-F_{\epsilon}(-xW) P(y=1)=1Fϵ(xW)
      
       F ϵ ( − x W ) F_{\epsilon}(-xW) Fϵ(xW)是正态分布函数的累积函数,上述累积分布函数,在服从正态分布的时候比较麻烦,因为正态分布的累积函数还没有解析表达式能够表达。 从而其参数估计非常麻烦,如果需要应用,则需要简化( 做近似处理 )。
      为了解决正态分布累积函数的问题,正态分布的累积函数的计算居然是通过查表的形式提供运算结果,大家如果想不起,可以查阅自己的高中数据或者大学数学书。

  5. 正态分布的近似处理
      正态分布表示:
       p ( x ) = 1 2 π σ e x p ( − ( x − μ ) 2 2 σ 2 ) p(x)=\dfrac{1}{\sqrt{2\pi}\sigma}exp(-\dfrac{(x-\mu)^2}{2\sigma^2}) p(x)=2π σ1exp(2σ2(xμ)2)    其中:μ表示期望(均数),σ表示标准差,σ2表示方差
      
      记正态分布为 N ( μ , σ ) N(μ,σ) N(μσ) ,标准正态分布是 N ( 0 , 1 ) N( 0,1 ) N(01)
      
       我们可以简化下正态分布累积函数的表示:
       F ϵ ( x ) = ϕ ( x − μ σ ) F_{\epsilon}(x)=\phi(\dfrac{x-\mu}{\sigma}) Fϵ(x)=ϕ(σxμ)
      因为 x − μ σ \dfrac{x-\mu}{\sigma} σxμ是线性,所以只需要考虑标准正态分布。
      在数学上存在一个逻辑分布,与正态分布非常相似,

  6. 逻辑分布与标准正态分布
      下面使用可视化来认识下逻辑分布函数与正态分布函数的近似度。
        |- 正态分布: p ( x ) = 1 2 π σ e x p ( − ( x − μ ) 2 2 σ 2 ) p(x)=\dfrac{1}{\sqrt{2\pi}\sigma}exp(-\dfrac{(x-\mu)^2}{2\sigma^2}) p(x)=2π σ1exp(2σ2(xμ)2)
        |- 逻辑分布: p ( x ) = e − x ( 1 + e − x ) 2 p(x)=\dfrac{e^{-x}}{(1+e^{-x})^2} p(x)=(1+ex)2ex
      
      逻辑分布函数与正态分布的区别就在于:逻辑分布有累积函数,其累积函数如下:
        |- 逻辑分布累积函数: S ( x ) = 1 1 + e − x S(x)=\dfrac{1}{1+e^{-x}} S(x)=1+ex1
      
      下面是逻辑分布函数,正态分布函数的比较:

% 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)
  1. 逻辑分布与标准正态分布的累积函数
      标准正态分布没有累积函数,所以我们采用scipy的积分函数来绘制。
      使用积分表示正态分布累积函数的公式如下:
        |- F ϵ ( x ) = ∫ − ∞ x 1 2 π σ e x p ( − ( t − μ ) 2 2 σ 2 ) d t F_{\epsilon}(x)=\int_{-\infty}^{x}\dfrac{1}{\sqrt{2\pi}\sigma}exp(-\dfrac{(t-\mu)^2}{2\sigma^2})\mathrm{d} t Fϵ(x)=x2π σ1exp(2σ2(tμ)2)dt
% 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)
  1. 最佳的逻辑分布
      如果逻辑分布参数做一些调整,可以最佳接近。下面是最佳逻辑分布累积函数表示:
        |- S ( x ) = 1 1 + e − 1.702 x S(x)=\dfrac{1}{1+e^{-1.702x}} S(x)=1+e1.702x1
      下面是可视化后的直观效果。
% 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函数
   S ( x ) = 1 1 + e − 1.702 x S(x)=\dfrac{1}{1+e^{-1.702x}} S(x)=1+e1.702x1 就是鼎鼎大名的sigmoid函数,该函数具备许多良好的性质。尤其是深度学习中的大杀器!经常会用到。
  函数的特点:
    |- 函数的导数可以用自身表示: S ′ ( x ) = S ( x ) ( 1 − S ( x ) ) S^\prime(x)=S(x)(1-S(x)) S(x)=S(x)(1S(x))
    |- 连续处处可微
    |- 值在[0,1)范围
    |- 单调递增
    |- 非线性
    |- 平滑性
    |- 原点附近近似identity(f(x)≈x)或者先线性性。
  函数的缺点:
    |- 运算量大(后面使用梯度下降算法可以提现出来,尤其误差传递的时候)
    |- 容易出现梯度消失的情况,从而不利于样本训练,甚至完不成梯度训练。(大家可以从逻辑分布函数看得出来,sigmoid函数的导数就是逻辑分布函数,逻辑分布函数从0开始,就逐步趋向于0,容易产生梯度消失)

二. 利用pytorch和numpy模块对数据集进行处理

模型

  • 预测:

    • y = S ( x W + b ) y = S(xW + b) y=S(xW+b)
  • 最好 W , b W, b W,b就是是下面损失函数最小的 W , b W, b W,b

    • 损失函数:交叉熵函数

实现

  1. 加载数据集

  2. 定义学习的w, b

循环

  1. 计算预测值
  2. 使用交叉熵计算损失值
  3. 求导数
  4. 更新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}")

结果如下

结果
结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值