1. 实验原理

1.1 数据输入

本实验中,给出了如下两类散点,其分布如下图所示:

1.2 定义前向模型

准备好数据之后,接着就是定义前向过程,从上一章节可以知道,逻辑回归算法实现分类时,有两个输入特征,即公式为:。因此在“定义前向模型”组件中,需要保证输入特征数量为2,输出1个特征,使用Sigmoid()函数分成两类,即 是一类,

是一类。

当输入是两个节点的时候,会有两个w1和w2

讲解一下为什么二元交叉熵为可以做损失函数?

讲解一下逻辑回归+二元交叉熵 和softmax+多分类交叉熵的区别?

逻辑回归+二元交叉熵

逻辑回归神经网络示意图

对计算出的结果结合二分类交叉熵进行计算损失。

eg: 实际标签为 0,预测值为0.1

计算方式:

eg: 实际标签为 1,预测值为0.8

二分类交叉熵

在二分类情况下,模型最后需要预测的结果只有两种情况,对于每个类别我们的预测得到的概率为p和1-p,此时表示式为(log的底数为e):

softmax+普通交叉熵

输出计算公式

使用softmax对输出进行计算概率

对计算出的结果结合多分类交叉熵进行计算损失。

多分类交叉熵

多分类交叉熵就是对二分类的交叉熵的扩展,在计算公式中和二分类稍微有些区别,但是还是比较容易理解,具体公式如下所示:

例子:

比如分三类有猫、狗、牛三类,真实标签是狗的话,可以表示为[0,1,0] onehot编码。真实标签是猫的话,可以表示为[1,0,0] onehot编码,真实标签是牛的话可以表示为[0,0,1]

1.3 定义损失函数和优化器

在选择好前向模型后,需要接着选择使用哪种损失函数和优化器,在“定义损失函数和优化器”组件中,提供的损失函数是交叉熵,优化器是SGD(随机梯度下降),学习率有多个选项,比如0.5、0.1、0.05…,建议选择较大的学习率,可以很快获得分类结果。

1.5 更新模型参数并显示

选择好迭代次数后,就需要设置一个显示频率,用来观察迭代过程中参数和损失值的变化,如下图所示:

接着就是观察迭代过程中参数和损失值的变化,通过“决策边界绘制与输出”组件即可观察,其内容如下:

代码

pytroch 框架的逻辑回归(sigmoid)无图)

import torch
import torch.nn as nn
import numpy as np
import torch.optim as optimizer

# 1.散点输入 包含蓝色点和红色点
class1_points=np.array([[1.9,1.2],
                        [1.5,2.1],
                        [1.9,0.5],
                        [1.5,0.9],
                        [0.9,1.2],
                        [1.1,1.7],
                        [1.4,1.1]])
class2_points=np.array([[3.2,3.2],
                        [3.7,2.9],
                        [3.2,2.6],
                        [1.7,3.3],
                        [3.4,2.6],
                        [4.1,2.3],
                        [3.0,2.9]])
#不用单独提取出x1_data和x2_data,框架会根据输入特征数自动提取
x_train=np.concatenate((class1_points,class2_points),axis=0)
y_train=np.concatenate((np.zeros(len(class1_points)),np.ones(len(class2_points))),axis=0)
#转成张量
x_train_tensor=torch.tensor(x_train,dtype=torch.float32)
y_train_tensor=torch.tensor(y_train,dtype=torch.float32)
print(y_train_tensor.shape)

#定义前向传播模型
#设置一下随机数种子
seed=42
torch.manual_seed(seed)
class LogisticRegreModel(nn.Module):
    def __init__(self):
        #继承父类
        super(LogisticRegreModel,self).__init__()
        #定义层 全连接层
        self.fc=nn.Linear(2,1)
    def forward(self,x):
        x=self.fc(x)
        x=torch.sigmoid(x)
        return x
#实例化网络
model=LogisticRegreModel()
#定义损失函数
cri=nn.BCELoss()
#定义优化器
#学习率为超参数
lr=0.05
optimizer=optimizer.SGD(model.parameters(),lr=lr)

#迭代
epoches=1000
for epoch in range(1,epoches+1):
    y_pre=model(x_train_tensor)
    #计算损失函数
    loss=cri(y_pre,y_train_tensor.unsqueeze(1))
    #反向传播和清理梯度
    optimizer.zero_grad()
    # 第二步反向传播
    loss.backward()
    #第三步参数更新
    optimizer.step()
    print(loss.item())

pytroch 框架的逻辑回归(sigmoid)有图)

#导入包
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optimizer
import matplotlib.pyplot as plt
# 1.散点输入
class1_points=np.array([[1.9,1.2],
                        [1.5,2.1],
                        [1.9,0.5],
                        [1.5,0.9],
                        [0.9,1.2],
                        [1.1,1.7],
                        [1.4,1.1]])
class2_points=np.array([[3.2,3.2],
                        [3.7,2.9],
                        [3.2,2.6],
                        [1.7,3.3],
                        [3.4,2.6],
                        [4.1,2.3],
                        [3.0,2.9]])
#不用单独提取出x1_data 和x2_data
#框架会根据输入特征数自动提取
x_train=np.concatenate((class1_points,class2_points),axis=0)
y_train=np.concatenate((np.zeros(len(class1_points)),np.ones(len(class2_points))))
#转化为张量
x_train_tensor=torch.tensor(x_train,dtype=torch.float32)
y_train_tensor=torch.tensor(y_train,dtype=torch.float32)
print('s')
#2.定义前向模型
# 使用类的方式
# 先设置一下随机数种子
seed=42
torch.manual_seed(seed)
class LogisticRegreModel(nn.Module):
    def __init__(self):
        #继承父类
        super(LogisticRegreModel,self).__init__()
        #定义层 全连接层
        self.fc=nn.Linear(2,1)
    #定义forward
    def forward(self,x):
        x=self.fc(x)
        #调用激活函数sigmoid获得返回值
        x=torch.sigmoid(x)
        return x
#实例化网络
model=LogisticRegreModel()
#3.定义损失函数和优化器
# 导入优化器的包
#定义二分类交叉熵损失函数
cri=nn.BCELoss()
#定义优化器
#需要输入模型参数和学习率
lr=0.05
optimizer=optimizer.SGD(model.parameters(),lr=lr)
# 最后画图
fig,(ax1,ax2)=plt.subplots(1,2)

epoch_list=[]
epoch_loss=[]
#4.开始迭代
epoches=1000
for epoch in range(1,epoches+1):
    y_pre=model(x_train_tensor)
    # cri前面是预测值,后面是目标值
    #将y_train_tensor 处理成和模型输出一样的维度
    loss=cri(y_pre,y_train_tensor.unsqueeze(1))
    #反向传播和优化
    # 第一步优化器清零
    optimizer.zero_grad()
    #第二步反向传播
    loss.backward()
    #第三步参数更新
    optimizer.step()

    if epoch%50==0 or epoch==1:
        print(f"epoch:{epoch},loss:{loss.item()}")
        w1,w2=model.fc.weight.data[0]
        b=model.fc.bias.data[0]

        #画左图
        # 使用斜率和截距画直线
        #目前将x2当作y轴 x1当作x轴
        # w1*x1+w2*x2+b=0
        #求出斜率和截距
        slope=-w1/w2
        intercept=-b/w2
        #绘制直线 开始结束位置
        x_min,x_max=0,5
        x=np.array([x_min,x_max])
        y=slope*x+intercept
        ax1.clear()
        ax1.plot(x,y,'r')
        #画散点图
        ax1.scatter(x_train[:len(class1_points),0],x_train[:len(class1_points),1])
        ax1.scatter(x_train[len(class1_points):, 0],x_train[len(class1_points):, 1])


        #画右图
        ax2.clear()
        epoch_list.append(epoch)
        epoch_loss.append(loss.item())
        ax2.plot(epoch_list,epoch_loss,'b')
        plt.pause(1)

pytroch 框架的逻辑回归(softmax)无图)

import torch
import torch.nn as nn
import numpy as np
import torch.optim as optimizer

# 1.散点输入 包含蓝色点和红色点
class1_points=np.array([[1.9,1.2],
                        [1.5,2.1],
                        [1.9,0.5],
                        [1.5,0.9],
                        [0.9,1.2],
                        [1.1,1.7],
                        [1.4,1.1]])
class2_points=np.array([[3.2,3.2],
                        [3.7,2.9],
                        [3.2,2.6],
                        [1.7,3.3],
                        [3.4,2.6],
                        [4.1,2.3],
                        [3.0,2.9]])
#不用单独提取出x1_data和x2_data,框架会根据输入特征数自动提取
x_train=np.concatenate((class1_points,class2_points),axis=0)
y_train=np.concatenate((np.zeros(len(class1_points)),np.ones(len(class2_points))),axis=0)
#转成张量
x_train_tensor=torch.tensor(x_train,dtype=torch.float32)
y_train_tensor=torch.tensor(y_train,dtype=torch.long)
print(y_train_tensor.shape)

#定义前向传播模型
#设置一下随机数种子
seed=42
torch.manual_seed(seed)
class LogisticRegreModel(nn.Module):
    def __init__(self):
        #继承父类
        super(LogisticRegreModel,self).__init__()
        #定义层 全连接层
        #使用softmax输出的特征为2
        self.fc=nn.Linear(2,2)
    def forward(self,x):
        x=self.fc(x)
        x=torch.softmax(x,dim=1)
        return x
#实例化网络
model=LogisticRegreModel()
#定义损失函数
cri=nn.CrossEntropyLoss()
#定义优化器
#学习率为超参数
lr=0.05
optimizer=optimizer.SGD(model.parameters(),lr=lr)

#迭代
epoches=1000
for epoch in range(1,epoches+1):
    y_pre=model(x_train_tensor)
    #计算损失函数
    loss=cri(y_pre,y_train_tensor)
    #反向传播和清理梯度
    optimizer.zero_grad()
    # 第二步反向传播
    loss.backward()
    #第三步参数更新
    optimizer.step()
    print(loss.item())

pytroch 框架的逻辑回归(softmax)有图)

#导入包
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optimizer
import matplotlib.pyplot as plt
# 1.散点输入
class1_points=np.array([[1.9,1.2],
                        [1.5,2.1],
                        [1.9,0.5],
                        [1.5,0.9],
                        [0.9,1.2],
                        [1.1,1.7],
                        [1.4,1.1]])
class2_points=np.array([[3.2,3.2],
                        [3.7,2.9],
                        [3.2,2.6],
                        [1.7,3.3],
                        [3.4,2.6],
                        [4.1,2.3],
                        [3.0,2.9]])
#不用单独提取出x1_data 和x2_data
#框架会根据输入特征数自动提取
x_train=np.concatenate((class1_points,class2_points),axis=0)
y_train=np.concatenate((np.zeros(len(class1_points)),np.ones(len(class2_points))))
#转化为张量
x_train_tensor=torch.tensor(x_train,dtype=torch.float32)
#标签得是整型
y_train_tensor=torch.tensor(y_train,dtype=torch.long)
print('s')
#2.定义前向模型
# 使用类的方式
# 先设置一下随机数种子
seed=42
torch.manual_seed(seed)
class LogisticRegreModel(nn.Module):
    def __init__(self):
        #继承父类
        super(LogisticRegreModel,self).__init__()
        #定义层 全连接层 sigmoid的输出特征是1
        # 使用softmax编程输出特征是2
        self.fc=nn.Linear(2,2)
    #定义forward
    def forward(self,x):
        x=self.fc(x)
        #调用激活函数softmax获得返回值
        #dim指定softmax在那个维度进行softmax,等于1是第2个维度,列上进行softmax
        #保持每一行的列元素和为1
        x=torch.softmax(x,dim=1)
        return x
#实例化网络
model=LogisticRegreModel()
#3.定义损失函数和优化器
# 导入优化器的包
#定义多分类交叉熵损失函数
cri=nn.CrossEntropyLoss()
#定义优化器
#需要输入模型参数和学习率
lr=0.05
optimizer=optimizer.SGD(model.parameters(),lr=lr)
# 最后画图
fig,(ax1,ax2)=plt.subplots(1,2)

epoch_list=[]
epoch_loss=[]
#4.开始迭代
epoches=1000
for epoch in range(1,epoches+1):
    y_pre=model(x_train_tensor)
    # cri前面是预测值,后面是目标值
    #将y_train_tensor 处理成和模型输出一样的维度
    loss=cri(y_pre,y_train_tensor)
    #反向传播和优化
    # 第一步优化器清零
    optimizer.zero_grad()
    #第二步反向传播
    loss.backward()
    #第三步参数更新
    optimizer.step()

    if epoch%50==0 or epoch==1:
        print(f"epoch:{epoch},loss:{loss.item()}")
        # 画左图
        # w是矩阵这里是2x2的矩阵
        # 直接画决策边界
        # 画决策边界需要数据
        ax1.clear()
        xx, yy = np.meshgrid(np.arange(0, 6, 0.1), np.arange(0, 6, 0.1))
        # 做成(x,y)对 前需要先对xx 和yy进行展平
        # 将输入的对象按照 np.c_ 按照第2个轴拼接
        grid_xy = np.c_[xx.ravel(), yy.ravel()]
        # print(xx)
        # 放进模型进行预测 前先转化为tensor
        grid_xy_tensor = torch.tensor(grid_xy, dtype=torch.float32)
        y_pre = torch.softmax(model(grid_xy_tensor), dim=1)
        # 获得标签值
        # detach().numpy()用于将一个Tensor从计算图中分离出来,并将其转换为一个NumPy数组
        pre_lables = np.argmax(y_pre.detach().numpy(), axis=1).reshape(xx.shape)
        #画等高线
        ax1.contour(xx, yy, pre_lables)
        # 画散点图
        ax1.scatter(x_train[:len(class1_points), 0], x_train[:len(class1_points), 1])
        ax1.scatter(x_train[len(class1_points):, 0], x_train[len(class1_points):, 1])
        #画右图
        ax2.clear()
        epoch_list.append(epoch)
        epoch_loss.append(loss.item())
        ax2.plot(epoch_list,epoch_loss,'b')
        plt.pause(1)
        print('s')

#5.显示频率设置
plt.show()
print('y')

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐