跳到主要内容

多层感知机

多层感知机 (MLP) 是一类深度神经网络,其特点是分层结构,包括一个输入层、一个或多个隐藏层以及一个输出层。每个层都包含神经元,这些神经元通过加权连接与后续层中的神经元完全连接。

多层感知机的结构

  • 输入层
    • 接收初始数据。
    • 将输入数据传递给第一个隐藏层。
  • 隐藏层
    • 对输入数据执行转换。
    • 利用非线性激活函数来建模复杂关系。
    • 每个神经元都连接到下一层的所有神经元。
  • 输出层
    • 产生最终的预测或分类。

神经元与权重

  • 神经元
    • 多层感知机处理输入数据的基本单元。
    • 对输入数据的加权和应用激活函数。
  • 权重
    • 确定神经元之间连接强度的参数。
    • 在训练过程中进行调整以最小化预测误差。

隐藏层

隐藏层对于使多层感知机能够捕获和建模数据中的复杂模式至关重要。它们通过结合非线性激活函数的转换来实现这一点。

隐藏层的作用

  • 数据转换

    • 将上一层的输入转换为适合下一层的形式。
  • 非线性激活函数

    • 引入非线性,使网络能够学习复杂的映射。
    • 对于网络逼近非线性函数的能力至关重要。

非线性的重要性

如果没有非线性激活函数,多层感知机将仅限于线性变换,无论层数多少,这会严重限制其建模能力。

激活函数

激活函数对于确定每个神经元的输出至关重要,它影响着网络的学习和表现能力。

ReLU (修正线性单元)

  • 定义

    ReLU(x)=max(x,0)\text{ReLU}(x) = \max(x, 0)
  • 特点

    • 保留正输入。
    • 将负输入转换为零。
    • 引入非线性。
    • 计算效率高。
  • 用途

    • 因其简单性和有效性而被广泛使用。
    • 有助于加快训练并缓解梯度消失问题。

Sigmoid 函数

  • 定义

    sigmoid(x)=11+exp(x)\text{sigmoid}(x) = \frac{1}{1 + \exp(-x)}
  • 特点

    • 将输入映射到 0 到 1 的范围。
    • 梯度平滑。
  • 用途

    • 适用于二元分类任务。
    • 具有历史意义,但在现代架构中因梯度消失等问题而较少受青睐。

Tanh 函数

  • 定义

    tanh(x)=1exp(2x)1+exp(2x)\text{tanh}(x) = \frac{1 - \exp(-2x)}{1 + \exp(2x)}
  • 特点

    • 将输入映射到 -1 到 1 的范围。
    • 使数据居中,改善学习动态。
  • 用途

    • 在某些情况下可能比 Sigmoid 更有效。
    • 有助于在训练过程中加快收敛。

万能逼近定理

万能逼近定理 指出,在隐藏层中拥有足够数量的神经元时,多层感知机可以逼近任何连续函数。这一理论基础突显了多层感知机在建模复杂函数方面的灵活性和强大能力。

实际考量

  • 网络架构

    • 隐藏层和神经元的数量会影响网络逼近函数的能力。
  • 权重初始化

    • 正确的初始化对于有效训练至关重要。
  • 训练算法

    • 优化方法和学习率影响网络的性能和收敛。

示例:PyTorch 实现

以下是使用 PyTorch(一个流行的深度学习框架)实现多层感知机的示例。

快速入门 — PyTorch 教程

有关全面的指南,请参考 快速入门 — PyTorch 教程

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

# 下载并加载数据集
train_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),
)

test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)

batch_size = 64
train_dataloader = DataLoader(train_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)

# 定义多层感知机模型
class MLP(nn.Module):
def __init__(self):
super(MLP, self).__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10)
)

def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits

# 设置设备、模型、损失函数和优化器
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MLP().to(device)
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)

# 训练和测试函数
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
model.train()
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)
pred = model(X)
loss = loss_fn(pred, y)

optimizer.zero_grad()
loss.backward()
optimizer.step()

if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")

def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f}")

# 运行训练和测试
epochs = 5
for epoch in range(epochs):
print(f"Epoch {epoch+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")

代码解释

  • 数据加载
    • 使用 FashionMNIST 数据集。
    • 将图像转换为张量格式进行处理。
  • 模型定义
    • MLP 类定义了网络架构。
    • 包含两个使用 ReLU 激活函数的隐藏层。
    • 输出层有 10 个神经元,对应 10 个类别。
  • 训练过程
    • 使用随机梯度下降 (SGD) 优化器。
    • 交叉熵损失函数衡量预测误差。
    • 训练循环遍历 epoch,更新权重以最小化损失。
  • 评估
    • 在测试数据集上评估模型的性能。
    • 报告准确率和平均损失。

参考资料和有用链接