当前位置: 首页 > news >正文

(四)动手实现多层感知机:深度学习中的非线性建模实战

1 多层感知机(MLP)

多层感知机(Multilayer Perceptron, MLP)是一种前馈神经网络,包含一个或多个隐藏层。它能够学习数据中的非线性关系,广泛应用于分类和回归任务。MLP的每个神经元对输入信号进行加权求和,然后通过激活函数引入非线性。

1.1 架构

MLP通常包含以下几部分:

  1. 输入层:接收输入特征。
  2. 隐藏层:一个或多个,每一层包含多个神经元。
  3. 输出层:产生最终的预测结果。

每层的输出作为下一层的输入。隐藏层的神经元通过激活函数引入非线性,使得模型能够学习复杂的模式。

1.2 激活函数

激活函数是神经元的输出函数,用于引入非线性。常见的激活函数包括:

  • ReLU(Rectified Linear Unit) ( ReLU ( x ) = max ⁡ ( 0 , x ) ) ( \text{ReLU}(x) = \max(0, x) ) (ReLU(x)=max(0,x))
  • Sigmoid ( Sigmoid ( x ) = 1 1 + e − x ) ( \text{Sigmoid}(x) = \frac{1}{1 + e^{-x}} ) (Sigmoid(x)=1+ex1)
  • Tanh ( Tanh ( x ) = e x − e − x e x + e − x ) ( \text{Tanh}(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} ) (Tanh(x)=ex+exexex)

激活函数的选择对模型的性能有重要影响。

1.3 训练过程

MLP的训练过程包括以下几个步骤:

  1. 前向传播:从输入层开始,逐层计算输出。
  2. 计算损失:通过损失函数(如交叉熵损失或均方误差损失)计算预测值与真实值之间的差异。
  3. 反向传播:计算损失函数关于每个参数的梯度。
  4. 参数更新:使用优化算法(如梯度下降法)更新模型参数。
1.4 应用场景

MLP可以应用于各种分类和回归任务,例如:

  • 图像分类:将图像的像素值作为输入,预测图像的类别。
  • 语音识别:将语音信号的特征作为输入,预测语音内容。
  • 自然语言处理:将文本的向量表示作为输入,预测文本的情感倾向等。
1.5 示例代码

以下是一个简单的MLP实现,使用PyTorch框架。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset# 模拟一些简单的数据
X = torch.randn(100, 2)
y = torch.randint(0, 2, (100,))# 定义MLP模型
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.layers = nn.Sequential(nn.Linear(2, 10),  # 输入层到隐藏层nn.ReLU(),         # 激活函数nn.Linear(10, 2)   # 隐藏层到输出层)def forward(self, x):return self.layers(x)# 实例化模型
model = MLP()# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)# 数据加载器
dataset = TensorDataset(X, y)
loader = DataLoader(dataset, batch_size=10, shuffle=True)# 训练模型
num_epochs = 100
for epoch in range(num_epochs):for inputs, targets in loader:# 前向传播outputs = model(inputs)loss = criterion(outputs, targets)# 反向传播optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 10 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
  • 隐藏层:隐藏层是MLP的核心,通过引入非线性激活函数,使得模型能够学习复杂的模式。
  • 激活函数:激活函数引入非线性,使得模型能够处理非线性问题。
  • 反向传播:反向传播是训练MLP的关键,通过计算损失函数的梯度,更新模型参数,最小化损失函数。
  • 优化算法:选择合适的优化算法(如SGD、Adam等)对模型的训练效果有重要影响。

通过理解多层感知机的架构和训练过程,你可以更好地应用它来解决实际问题。

2 激活函数

激活函数是神经网络中每个神经元的输出函数,用于引入非线性,使得模型能够学习复杂的模式。以下是几种常见的激活函数及其特点:

2.1. ReLU(Rectified Linear Unit)
  • 公式 ( ReLU ( x ) = max ⁡ ( 0 , x ) ) ( \text{ReLU}(x) = \max(0, x) ) (ReLU(x)=max(0,x))
  • 特点:计算简单,收敛速度快,常用于隐藏层。但存在“神经元死亡”问题(当输入为负时,梯度为零)。
  • 应用场景:广泛应用于卷积神经网络和多层感知机。
2.2. Sigmoid
  • 公式 ( Sigmoid ( x ) = 1 1 + e − x ) ( \text{Sigmoid}(x) = \frac{1}{1 + e^{-x}} ) (Sigmoid(x)=1+ex1)
  • 特点:输出范围在 (0, 1),可用于二分类问题的输出层。但容易出现梯度消失问题(当输入绝对值较大时,梯度趋近于零)。
  • 应用场景:二分类问题的输出层。
2.3. Tanh(双曲正切函数)
  • 公式 ( Tanh ( x ) = e x − e − x e x + e − x ) ( \text{Tanh}(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} ) (Tanh(x)=ex+exexex)
  • 特点:输出范围在 (-1, 1),比 Sigmoid 收敛更快,但同样存在梯度消失问题。
  • 应用场景:隐藏层。
2.4. Leaky ReLU
  • 公式 ( Leaky ReLU ( x ) = max ⁡ ( 0.01 x , x ) ) ( \text{Leaky ReLU}(x) = \max(0.01x, x) ) (Leaky ReLU(x)=max(0.01x,x))
  • 特点:解决了 ReLU 的“神经元死亡”问题,通过引入一个较小的斜率(如 0.01)来处理负值输入。
  • 应用场景:需要避免神经元死亡问题的场景。
2.5. ELU(Exponential Linear Unit)
  • 公式 ( ELU ( x ) = { x , x > 0 α ( e x − 1 ) , x ≤ 0 ) ( \text{ELU}(x) = \begin{cases} x, & x > 0 \\ \alpha(e^x - 1), & x \leq 0 \end{cases} ) (ELU(x)={x,α(ex1),x>0x0)
  • 特点:在负值区域引入非线性,有助于缓解梯度消失问题。参数 α \alpha α通常设置为 1.0。
  • 应用场景:需要更好的收敛性能的场景。
2.6. Swish
  • 公式 ( Swish ( x ) = x ⋅ Sigmoid ( x ) ) ( \text{Swish}(x) = x \cdot \text{Sigmoid}(x) ) (Swish(x)=xSigmoid(x))
  • 特点:由 Google 提出,具有平滑的非线性特性,通常比 ReLU 表现更好。
  • 应用场景:各种深度学习任务。
2.7 激活函数的比较
激活函数优点缺点应用场景
ReLU计算简单,收敛快神经元死亡问题隐藏层
Sigmoid输出范围固定梯度消失问题二分类输出层
Tanh输出范围对称梯度消失问题隐藏层
Leaky ReLU解决神经元死亡问题需要调整斜率参数需要避免神经元死亡的场景
ELU缓解梯度消失问题计算稍复杂需要更好收敛性能的场景
Swish平滑非线性,性能好计算稍复杂各种深度学习任务
2.8 代码示例

以下是使用PyTorch实现几种常见激活函数的示例:

import torch
import torch.nn as nn
import matplotlib.pyplot as plt# 定义输入数据
x = torch.linspace(-5, 5, 100)# 定义激活函数
relu = nn.ReLU()
sigmoid = nn.Sigmoid()
tanh = nn.Tanh()
leaky_relu = nn.LeakyReLU(0.01)
elu = nn.ELU()
swish = nn.SiLU()  # PyTorch 1.7+ 支持 Swish# 计算输出
y_relu = relu(x)
y_sigmoid = sigmoid(x)
y_tanh = tanh(x)
y_leaky_relu = leaky_relu(x)
y_elu = elu(x)
y_swish = swish(x)# 绘制图像
plt.figure(figsize=(12, 8))plt.subplot(2, 3, 1)
plt.plot(x.numpy(), y_relu.numpy(), label='ReLU')
plt.xlabel('x')
plt.ylabel('y')
plt.title('ReLU')
plt.grid(True)plt.subplot(2, 3, 2)
plt.plot(x.numpy(), y_sigmoid.numpy(), label='Sigmoid', color='orange')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Sigmoid')
plt.grid(True)plt.subplot(2, 3, 3)
plt.plot(x.numpy(), y_tanh.numpy(), label='Tanh', color='green')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Tanh')
plt.grid(True)plt.subplot(2, 3, 4)
plt.plot(x.numpy(), y_leaky_relu.numpy(), label='Leaky ReLU', color='red')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Leaky ReLU')
plt.grid(True)plt.subplot(2, 3, 5)
plt.plot(x.numpy(), y_elu.numpy(), label='ELU', color='purple')
plt.xlabel('x')
plt.ylabel('y')
plt.title('ELU')
plt.grid(True)plt.subplot(2, 3, 6)
plt.plot(x.numpy(), y_swish.numpy(), label='Swish', color='brown')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Swish')
plt.grid(True)plt.tight_layout()
plt.show()
  • 非线性:激活函数的主要作用是引入非线性,使得神经网络能够学习数据中的复杂模式。
  • 梯度消失:Sigmoid 和 Tanh 等激活函数在输入绝对值较大时,梯度趋近于零,导致训练过程变慢。
  • 选择合适的激活函数:根据具体任务和网络结构选择合适的激活函数,可以显著提高模型的性能和训练效率。

通过理解不同激活函数的特点和应用场景,你可以更好地选择和应用它们来构建高效的神经网络模型。

3 多层感知机的从零开始实现

使用Python和PyTorch从零开始实现一个多层感知机(MLP)。我们将逐步构建模型,包括数据准备、模型定义、训练和评估。

3.1 数据准备

首先,我们需要准备一些用于训练的数据。这里我们使用一个简单的二维数据集,目标是将其分类为两个类别。

import numpy as np
import matplotlib.pyplot as plt# 生成数据集
np.random.seed(42)
X = np.random.rand(100, 2)  # 100个样本,每个样本2个特征
y = (X[:, 0] + X[:, 1] > 1).astype(np.int64)  # 简单的分类规则# 绘制数据
plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='red', label='Class 0')
plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='blue', label='Class 1')
plt.xlabel('X1')
plt.ylabel('X2')
plt.title('Generated Data')
plt.legend()
plt.show()
3.2 定义模型

接下来,我们定义一个多层感知机模型。我们将实现一个包含一个隐藏层的MLP,隐藏层使用ReLU激活函数。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader# 转换为张量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.long)# 创建数据集和数据加载器
dataset = TensorDataset(X_tensor, y_tensor)
data_loader = DataLoader(dataset, batch_size=10, shuffle=True)# 定义模型
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.hidden = nn.Linear(2, 4)  # 输入特征维度为2,隐藏层维度为4self.output = nn.Linear(4, 2)  # 隐藏层维度为4,输出维度为2def forward(self, x):x = torch.relu(self.hidden(x))  # 使用ReLU激活函数x = self.output(x)return xmodel = MLP()
3.3 定义损失函数和优化器

我们使用交叉熵损失函数和随机梯度下降优化器来训练模型。

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
3.4 训练模型

现在,我们开始训练模型。我们将迭代多个周期,并在每个周期中执行前向传播、计算损失、执行反向传播和更新参数。

# 训练模型
num_epochs = 100
losses = []for epoch in range(num_epochs):for X_batch, y_batch in data_loader:# 前向传播y_pred = model(X_batch)loss = criterion(y_pred, y_batch)# 反向传播optimizer.zero_grad()loss.backward()optimizer.step()losses.append(loss.item())if (epoch + 1) % 10 == 0:print(f'Epoch {epoch + 1}, Loss: {loss.item():.4f}')# 绘制损失曲线
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.show()
3.5 模型评估

训练完成后,我们评估模型的性能,计算准确率。

# 计算准确率
model.eval()  # 设置为评估模式
with torch.no_grad():y_pred = model(X_tensor)_, predicted = torch.max(y_pred, 1)accuracy = (predicted == y_tensor).sum().item() / len(y_tensor)print(f'Accuracy: {accuracy * 100:.2f}%')
3.6 可视化决策边界

为了更好地理解模型的分类效果,我们可以可视化决策边界。

# 可视化决策边界
h = .02  # 网格步长
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))# 计算模型预测
Z = model(torch.tensor(np.c_[xx.ravel(), yy.ravel()], dtype=torch.float32))
Z = torch.max(Z, 1)[1].numpy().reshape(xx.shape)# 绘制决策边界
plt.contourf(xx, yy, Z, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', marker='o')
plt.xlabel('X1')
plt.ylabel('X2')
plt.title('Decision Boundary')
plt.show()
3.7 完整代码

将上述代码整合在一起,可以直接运行以下代码来实现多层感知机模型的从零开始实现:

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import matplotlib.pyplot as plt# 生成数据集
np.random.seed(42)
X = np.random.rand(100, 2)  # 100个样本,每个样本2个特征
y = (X[:, 0] + X[:, 1] > 1).astype(np.int64)  # 简单的分类规则# 转换为张量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.long)# 创建数据集和数据加载器
dataset = TensorDataset(X_tensor, y_tensor)
data_loader = DataLoader(dataset, batch_size=10, shuffle=True)# 定义模型
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.hidden = nn.Linear(2, 4)  # 输入特征维度为2,隐藏层维度为4self.output = nn.Linear(4, 2)  # 隐藏层维度为4,输出维度为2def forward(self, x):x = torch.relu(self.hidden(x))  # 使用ReLU激活函数x = self.output(x)return xmodel = MLP()# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)# 训练模型
num_epochs = 100
losses = []for epoch in range(num_epochs):for X_batch, y_batch in data_loader:# 前向传播y_pred = model(X_batch)loss = criterion(y_pred, y_batch)# 反向传播optimizer.zero_grad()loss.backward()optimizer.step()losses.append(loss.item())if (epoch + 1) % 10 == 0:print(f'Epoch {epoch + 1}, Loss: {loss.item():.4f}')# 绘制损失曲线
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.show()# 计算准确率
model.eval()  # 设置为评估模式
with torch.no_grad():y_pred = model(X_tensor)_, predicted = torch.max(y_pred, 1)accuracy = (predicted == y_tensor).sum().item() / len(y_tensor)print(f'Accuracy: {accuracy * 100:.2f}%')# 可视化决策边界
h = .02  # 网格步长
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))# 计算模型预测
Z = model(torch.tensor(np.c_[xx.ravel(), yy.ravel()], dtype=torch.float32))
Z = torch.max(Z, 1)[1].numpy().reshape(xx.shape)# 绘制决策边界
plt.contourf(xx, yy, Z, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', marker='o')
plt.xlabel('X1')
plt.ylabel('X2')
plt.title('Decision Boundary')
plt.show()

4 多层感知机的简洁实现

利用 PyTorch 提供的高级 API 来构建多层感知机(MLP),这将帮助我们更加高效地实现模型,减少手动定义和管理模型细节的工作量。

4.1 构建多层感知机
4.1.1. 导入必要的库

首先,我们需要导入 PyTorch 中的相关模块,这些模块将被用于定义模型、优化器以及数据加载器等。

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
4.1.2. 定义 MLP 模型

使用 PyTorch 的 nn.Module 定义一个简单的多层感知机,包含一个隐藏层。这里我们定义一个简单的两层神经网络,隐藏层使用 ReLU 激活函数,输出层没有激活函数。

class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.fc1 = nn.Linear(784, 128)  # 输入层到隐藏层的线性变换self.fc2 = nn.Linear(128, 10)   # 隐藏层到输出层的线性变换def forward(self, x):x = F.relu(self.fc1(x))  # 隐藏层后应用 ReLU 激活函数x = self.fc2(x)return x
  • nn.Linear:定义了一个全连接层。
  • F.relu:将 ReLU 激活函数应用于隐藏层的输出。
4.1.3. 准备数据集

为了训练模型,我们需要一个数据集。这里我们使用 PyTorch 的 torchvision 库来加载 MNIST 数据集,并使用 DataLoader 将其封装为一个可迭代的数据加载器。

from torchvision import datasets, transforms
from torch.utils.data import DataLoader# 数据转换
transform = transforms.Compose([transforms.ToTensor(),  # 将图像数据转换为张量transforms.Normalize((0.1307,), (0.3081,))  # 标准化
])# 下载并加载训练集和测试集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
test_loader = DataLoader(test_dataset, batch_size=1000, shuffle=False)
4.1.4. 初始化模型和优化器

创建 MLP 模型的实例,并初始化优化器。这里我们使用随机梯度下降(SGD)优化器。

model = MLP()
optimizer = optim.SGD(model.parameters(), lr=0.01)
4.1.5. 训练模型

定义一个训练函数,执行模型的训练过程。这个过程包括前向传播、损失计算、反向传播和参数更新。

def train(model, device, train_loader, optimizer, epoch):model.train()for batch_idx, (data, target) in enumerate(train_loader):data, target = data.view(-1, 784).to(device), target.to(device)  # 将数据展平为 784 维的向量optimizer.zero_grad()output = model(data)loss = F.cross_entropy(output, target)  # 计算交叉熵损失loss.backward()optimizer.step()if batch_idx % 100 == 0:print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} ({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')
4.1.6. 测试模型

定义一个测试函数,评估模型在测试集上的性能。

def test(model, device, test_loader):model.eval()test_loss = 0correct = 0with torch.no_grad():for data, target in test_loader:data, target = data.view(-1, 784).to(device), target.to(device)output = model(data)test_loss += F.cross_entropy(output, target, reduction='sum').item()  # 将一批的损失相加pred = output.argmax(dim=1, keepdim=True)  # 获得概率最大的索引correct += pred.eq(target.view_as(pred)).sum().item()test_loss /= len(test_loader.dataset)print(f'\nTest set: Average loss: {test_loss:.4f}, Accuracy: {correct}/{len(test_loader.dataset)} ({100. * correct / len(test_loader.dataset):.0f}%)')
4.1.7. 定义设备并开始训练

在训练之前,定义使用的设备(CPU 或 GPU),然后开始训练和测试过程。

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)for epoch in range(1, 11):  # 进行 10 轮训练train(model, device, train_loader, optimizer, epoch)test(model, device, test_loader)
4.2 注意事项
  1. 数据预处理:数据预处理对于模型的性能至关重要。在 MNIST 数据集的例子中,我们进行了归一化处理,以提高模型的训练效率。
  2. 超参数调整:学习率、隐藏层大小、批次大小等超参数对模型的训练和测试性能有重要影响,需要根据具体任务进行调整。
  3. 模型复杂度:增加隐藏层或隐藏层神经元的数量可以提高模型的表示能力,但同时也会增加训练难度和计算成本。
  4. 过拟合和欠拟合:如果模型在训练集上表现很好,但在测试集上表现不佳,可能是过拟合;如果模型在训练集上表现也不好,可能是欠拟合。需要通过调整模型复杂度、增加数据量、使用正则化等方法来解决这些问题。

通过这种简洁的实现方式,我们可以快速地构建和训练一个基本的多层感知机模型,同时也可以方便地对模型进行扩展和优化,以适应更复杂的任务和数据集。

4.5 模型评估

评估训练后的模型性能,计算准确率:

# 计算准确率
model.eval()  # 设置为评估模式
with torch.no_grad():y_pred = model(X_tensor)_, predicted = torch.max(y_pred, 1)accuracy = (predicted == y_tensor).sum().item() / len(y_tensor)print(f'Accuracy: {accuracy * 100:.2f}%')

4.6 多层感知机的应用

多层感知机可以应用于各种分类和回归任务。通过增加隐藏层和调整网络结构,可以提高模型的性能和泛化能力。

多层感知机通过引入隐藏层和非线性激活函数,能够学习数据中的复杂模式,适用于各种分类和回归任务。

相关文章:

  • Windows 下彻底删除 VsCode
  • Neovim - 打造一款属于自己的编辑器(一)
  • 云计算 Linux Rocky day03
  • 【云计算】基础篇,含云测试
  • PyTorch——线性层及其他层介绍(6)
  • 酷狗概念版4.1.6深度体验:探索音乐新境界的便捷之选
  • 解决Vue3+uni-app导航栏高亮自动同步方案
  • 深入浅出:Oracle 数据库 SQL 执行计划查看详解(1)——基础概念与查看方式
  • 【Kotlin】表达式关键字
  • 前端与后端
  • 链表题解——反转链表【LeetCode】
  • uniapp+vue2+uView项目学习知识点记录
  • winrm登录失败,指定的凭据被服务器拒绝
  • git stash介绍(临时保存当前工作目录中尚未提交的修改)
  • Rust 学习笔记:使用 cargo install 安装二进制 crate
  • nav2笔记-250603
  • Linux运维笔记:1010实验室电脑资源规范使用指南
  • NSSCTF [LitCTF 2025]test_your_nc
  • 第二篇: 深入解析模型上下文协议(MCP):技术架构、核心组件与深远影响
  • 互联网c++开发岗位偏少,测开怎么样?
  • 建设网站条件/百度怎么发免费广告
  • frontpage可以做网站吗/职业培训机构排名前十
  • 广西建设工会网站/网络营销到底是个啥
  • 明星网站建设/seo推广关键词公司
  • 南康家具网站建设/网络推广团队
  • 莱芜共青团网站/北京seo公司网站