用神经网络实现二维数据分类:从代码到原理深度解析

        在机器学习领域,分类任务是最常见的应用场景之一。无论是图像识别、垃圾邮件过滤,还是疾病诊断,都离不开分类算法的支持。本文将通过一个简单的二维数据分类实例,详细介绍如何使用神经网络完成分类任务,帮助你理解神经网络的工作原理和实现过程。

一、数据生成:构建我们的数据集

        为了方便演示,我们首先使用代码生成一个简单的二维数据集。

n_samples = 100
data = torch.randn(n_samples, 2)  # 生成 100 个二维数据点
labels = (data[:, 0]**2 +
          data[:, 1]**2 < 1).float().unsqueeze(1)  # 点在圆内为1,圆外为0

        上述代码生成了 100 个符合标准正态分布的二维数据点,并且根据这些点是否在单位圆内,为每个点分配了一个标签。如果点在单位圆内,标签为 1;如果点在单位圆外,标签为 0。这就形成了一个简单的二分类数据集。

        为了更直观地观察数据分布,我们使用以下代码进行可视化:

plt.scatter(data[:, 0], data[:, 1], c=labels.squeeze(), cmap='coolwarm')
plt.title("Generated Data")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()

        运行代码后,我们可以看到数据点以不同颜色区分,清晰地展示出在单位圆内和圆外的分布情况。 

图1 生成的数据

二、模型构建:搭建神经网络架构

        接下来,我们需要定义一个神经网络模型来完成分类任务。这里我们构建了一个简单的前馈神经网络。

class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        # 定义神经网络的层
        self.fc1 = nn.Linear(2, 4)  # 输入层有 2 个特征,隐藏层有 4 个神经元
        self.fc2 = nn.Linear(4, 1)  # 隐藏层输出到 1 个神经元(用于二分类)
        self.sigmoid = nn.Sigmoid()  # 二分类激活函数

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 使用 ReLU 激活函数
        x = self.sigmoid(self.fc2(x))  # 输出层使用 Sigmoid 激活函数
        return x

        在这个模型中,我们定义了两个全连接层。fc1 层接收二维数据作为输入,并将其映射到包含 4 个神经元的隐藏层;fc2 层则将隐藏层的输出映射到单个神经元,用于输出分类结果。       

         在 forward 方法中,我们对 fc1 层的输出使用了 ReLU 激活函数,以引入非线性,而 fc2 层的输出则通过 Sigmoid 激活函数,将输出值压缩到 0 到 1 之间,方便我们将其解释为属于某一类别的概率。

三、训练准备:选择损失函数和优化器

        在训练模型之前,需要选择合适的损失函数和优化器。

criterion = nn.BCELoss()  # 二元交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.1)  # 使用随机梯度下降优化器

        对于二分类问题,二元交叉熵损失(BCELoss)是一个常用的选择,它能够有效地衡量模型预测概率与真实标签之间的差异。而随机梯度下降(SGD)优化器则通过不断调整模型参数,使损失函数最小化,从而让模型的预测结果更接近真实标签。这里我们设置学习率为 0.1,学习率决定了每次参数更新的步长,过大或过小都可能影响训练效果。

四、模型训练:让神经网络学习分类

        有了数据、模型、损失函数和优化器,我们就可以开始训练模型了。

epochs = 1000
for epoch in range(epochs):
    # 前向传播
    outputs = model(data)
    loss = criterion(outputs, labels)

    # 反向传播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 每 10 轮打印一次损失
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{epochs}], Loss: {loss.item():.4f}')

        在训练过程中,我们进行了 1000 个训练周期(epochs)。每个周期内,首先通过前向传播计算模型的预测输出,并根据预测输出和真实标签计算损失值。然后,通过反向传播计算损失对模型参数的梯度,使用优化器更新模型参数,以减小损失。每隔 10 个周期,我们打印当前的损失值,以便观察模型的训练进度和效果。随着训练的进行,我们可以看到损失值逐渐减小,说明模型在不断学习和优化。        

五、结果可视化:展示决策边界

        训练完成后,我们可以通过可视化决策边界来直观地展示模型的分类效果。

def plot_decision_boundary(model, data):
    x_min, x_max = data[:, 0].min() - 1, data[:, 0].max() + 1
    y_min, y_max = data[:, 1].min() - 1, data[:, 1].max() + 1
    xx, yy = torch.meshgrid(torch.arange(x_min, x_max, 0.1), torch.arange(y_min, y_max, 0.1), indexing='ij')
    grid = torch.cat([xx.reshape(-1, 1), yy.reshape(-1, 1)], dim=1)
    predictions = model(grid).detach().numpy().reshape(xx.shape)
    plt.contourf(xx, yy, predictions, levels=[0, 0.5, 1], cmap='coolwarm', alpha=0.7)
    plt.scatter(data[:, 0], data[:, 1], c=labels.squeeze(), cmap='coolwarm', edgecolors='k')
    plt.title("Decision Boundary")
    plt.show()

plot_decision_boundary(model, data)

        上述代码首先定义了一个函数 plot_decision_boundary ,用于绘制决策边界。通过生成一个二维网格,将网格中的每个点输入到训练好的模型中进行预测,然后根据预测结果绘制等高线图,从而展示出模型的决策边界。结合原始数据点的可视化,我们可以清晰地看到模型是如何对不同区域的数据进行分类的。

图2 预测结果

六、完整代码

        完整代码如下:

#假设有一个二维数据集,目标是根据点的位置将它们分类到两个类别中(例如,红色和蓝色点)。
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# 生成一些随机数据
n_samples = 100
data = torch.randn(n_samples, 2)  # 生成 100 个二维数据点

labels = (data[:, 0]**2 + 
          data[:, 1]**2 < 1).float().unsqueeze(1)  # 点在圆内为1,圆外为0

# 可视化数据
plt.scatter(data[:, 0], data[:, 1], c=labels.squeeze(), cmap='coolwarm')
plt.title("Generated Data")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()

# 定义前馈神经网络
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        # 定义神经网络的层
        self.fc1 = nn.Linear(2, 4)  # 输入层有 2 个特征,隐藏层有 4 个神经元
        self.fc2 = nn.Linear(4, 1)  # 隐藏层输出到 1 个神经元(用于二分类)
        self.sigmoid = nn.Sigmoid()  # 二分类激活函数

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 使用 ReLU 激活函数
        x = self.sigmoid(self.fc2(x))  # 输出层使用 Sigmoid 激活函数
        return x

# 实例化模型
model = SimpleNN()

# 定义损失函数和优化器
criterion = nn.BCELoss()  # 二元交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.1)  # 使用随机梯度下降优化器

# 训练
epochs = 1000
for epoch in range(epochs):
    # 前向传播
    outputs = model(data)
    loss = criterion(outputs, labels)

    # 反向传播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 每 10 轮打印一次损失
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{epochs}], Loss: {loss.item():.4f}')

# 可视化决策边界
def plot_decision_boundary(model, data):
    x_min, x_max = data[:, 0].min() - 1, data[:, 0].max() + 1
    y_min, y_max = data[:, 1].min() - 1, data[:, 1].max() + 1
    xx, yy = torch.meshgrid(torch.arange(x_min, x_max, 0.1), torch.arange(y_min, y_max, 0.1), indexing='ij')
    grid = torch.cat([xx.reshape(-1, 1), yy.reshape(-1, 1)], dim=1)
    predictions = model(grid).detach().numpy().reshape(xx.shape)
    plt.contourf(xx, yy, predictions, levels=[0, 0.5, 1], cmap='coolwarm', alpha=0.7)
    plt.scatter(data[:, 0], data[:, 1], c=labels.squeeze(), cmap='coolwarm', edgecolors='k')
    plt.title("Decision Boundary")
    plt.show()

plot_decision_boundary(model, data)

七、总结与思考

        通过这个二维数据分类的实例,我们完整地展示了从数据生成、模型构建、训练准备、模型训练到结果可视化的整个机器学习流程。虽然这个例子非常简单,但它涵盖了神经网络分类任务的核心步骤和关键概念,方便大家更好的理解分类问题和神经网络。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值