Logistic回归,多层全连接前向网络以及反向传播算法

本文介绍如何使用PyTorch实现Logistic回归,包括数据读取、模型定义、损失函数选择、优化器配置及训练过程。通过可视化展示原始数据分布、分类线及训练过程中的损失变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import matplotlib.pyplot as plt
from torch import nn, optim
import numpy as np
import torch
from torch.autograd import Variable

# 设置字体为中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# Hyper-parameters 超参数是在开始学习过程之前设置值的参数,而不是通过训练得到的参数数据
input_size = 2        #输入维度
output_size = 1        #输出维度
num_epochs = 50000       #迭代次数
learning_rate = 0.0001   #学习率 : 决定了参数移动到最优值的速度快慢。
                       #如果学习率过大,很可能会越过最优值;反而如果学习率过小,优化的效率可能过低,长时间算法无法收敛。
                       #所以学习率对于算法性能的表现至关重要。

# 读取数据
def readText():
    with open('data.txt', 'r') as f:
        data_list = f.readlines()
        data_list = [i.split('\n')[0] for i in data_list]
        data_list = [i.split(',') for i in data_list]
        data = [(float(i[0]), float(i[1]), int(i[2])) for i in data_list]
        x_data = [[float(i[0]), float(i[1])] for i in data_list]
        y_data = [float(i[2]) for i in data_list]
    return data, x_data, y_data


# 原始数据可视化
def visualize(data):
    x0 = list(filter(lambda x: x[-1] == 0.0, data))  # 找出类别为0的数据集
    x1 = list(filter(lambda x: x[-1] == 1.0, data))  # 找出类别为1的数据集
    plot_x0_0 = [i[0] for i in x0]  # 类别0的x
    plot_x0_1 = [i[1] for i in x0]  # 类别0的y
    plot_x1_0 = [i[0] for i in x1]  # 类别1的x
    plot_x1_1 = [i[1] for i in x1]  # 类别1的y
    plt.plot(plot_x0_0, plot_x0_1, 'ro', label='类别 0')
    plt.plot(plot_x1_0, plot_x1_1, 'bo', label='类别 1')
    plt.legend()  # 显示图例
    # plt.title(label='原始数据分布情况')
    plt.show()


def visualize_after(data):
    #lambda用于产生一个匿名表达式,组成部分为:lambda + 函数表达式。 函数表达式由一个冒号加上两个 操作数 组成
    #冒号左边的操作数,作为函数的参数;冒号右边的作为函数的放回值。
    #x[-1] 逆向遍历 data
    x0 = list(filter(lambda x: x[-1] == 0.0, data))  # 找出类别为0的数据集
    x1 = list(filter(lambda x: x[-1] == 1.0, data))  # 找出类别为1的数据集
    plot_x0_0 = [i[0] for i in x0]  # 类别0的x
    plot_x0_1 = [i[1] for i in x0]  # 类别0的y
    plot_x1_0 = [i[0] for i in x1]  # 类别1的x
    plot_x1_1 = [i[1] for i in x1]  # 类别1的y
    plt.plot(plot_x0_0, plot_x0_1, 'ro', label='类别 0')
    plt.plot(plot_x1_0, plot_x1_1, 'bo', label='类别 1')
    # 绘制分类函数(直线方程)
    w0, w1 = model.lr.weight[0]
    w0 = w0.data.item()
    w1 = w1.data.item()
    b = model.lr.bias.item()
    plot_x = np.arange(30, 100, 0.1)  # x从30 到 100,步进为0.1
    plot_y = (-w0 * plot_x - b) / w1  # w1*x +w2*y+b=0
    plt.plot(plot_x, plot_y, 'yo', label='分类线')
    plt.legend()  # 显示图例
    # plt.title(label='分类线可视化')
    plt.show()


# Logistic回归模型
class LogisticRegression(nn.Module):
    def __init__(self):
        super(LogisticRegression, self).__init__()
        self.lr = nn.Linear(input_size, output_size)
        self.sm = nn.Sigmoid()  # 激活函数类型为sigmoid,经过激活函数,值控制在0到1之间

    def forward(self, x):
        x = self.lr(x)
        x = self.sm(x)
        return x

# 主函数(if __name__ == '__main__'象征主函数开始)
if __name__ == '__main__':
    data, x_data, y_data = readText()  # 读取数据

    x_data = torch.from_numpy(np.array(x_data))
    y_data = torch.from_numpy(np.array(y_data))

    visualize(data)  # 可视化(观察原始数据分布情况)
    # 获取到模型
    model = LogisticRegression()
    # if torch.cuda.is_available():
    #     model.cuda()
    # 损失函数以及梯度下降
    criterion = nn.BCELoss()  # 二分类的损失函数
    # momentum 动量,避免算法在某些情况下,过早局部收敛。
    # 每次参数修改的方向由上一次参数修改方向和本次梯度方向共同决定
    optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)

    ctn = []
    lo = []
    for epoch in range(num_epochs):
        # if torch.cuda.is_available():
        #     x = Variable(x_data).cuda()
        #     y = Variable(y_data).cuda()
        # else:
        #     x = Variable(x_data)
        #     y = Variable(y_data)
        x = Variable(x_data)
        y = Variable(y_data)

        x = torch.tensor(x, dtype=torch.float32)
        out = model(x)
        y = torch.tensor(y, dtype=torch.float32)
        loss = criterion(out, y)
        print_loss = loss.data.item()
        mask = out.ge(0.5).float()  # 将结果大于0.5的归类为1,结果小于0.5的归类为0
        correct = (mask == y).sum()  # 统计输出为1的个数
        acc = correct.item() / x.size(0)

        optimizer.zero_grad()  # 梯度清零
        loss.backward()  # 反向传播
        optimizer.step()  # 更新梯度

        #将迭代次数和损失分别保存起来
        ctn.append(epoch + 1)
        lo.append(print_loss)

        if (epoch + 1) % 1000 == 0:
            print('*' * 10)
            print('epoch {}'.format(epoch + 1))
            print('loss is {:.4f}'.format(print_loss))
            print('acc is {:.4f}'.format(acc/10.0))

    visualize_after(data)
    # 绘制训练次数与损失值之间的关系
    plt.plot(ctn, lo)
    # plt.title(label='训练次数与损失值关系')
    plt.xlabel('训练次数')
    plt.ylabel('损失值')
    plt.show()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值