【PyTorch】多层感知机

1. 理论介绍

1.1. 背景

许多问题要使用线性模型,但无法简单地通过预处理来实现。此时我们可以通过在网络中加入一个或多个隐藏层来克服线性模型的限制, 使其能处理更普遍的函数关系类型。

1.2. 多层感知机

将许多全连接层堆叠在一起。 每一层都输出到上面的层,直到生成最后的输出,我们可以把前层看作表示,把最后一层看作线性预测器。 这种架构通常称为多层感知机,通常缩写为MLP。
多层感知机

1.3. 激活函数

我们需要在仿射变换之后对每个隐藏单元应用非线性的激活函数,这样就不可能再将我们的多层感知机退化成线性模型,使得模型具有更强的表达能力。
激活函数是通过计算加权和并加上偏置来确定神经元是否应该被激活, 并将输入信号转换为输出的可微运算的函数。

1.3.1. ReLU函数

  • 修正线性单元(Rectified linear unit,ReLU)。
  • 最受欢迎的激活函数。
  • 定义: R e L U ( x ) = m a x ( 0 , x ) \mathrm{ReLU}(x)=\mathrm{max}(0,x) ReLU(x)=max(0,x)
    relu
  • 当输入接近0时,sigmoid函数接近线性变换。
    gradofrelu
  • 当输入值精确等于0时,ReLU函数不可导。 在此时,我们默认使用左侧的导数,即当输入为0时导数为0。 我们可以忽略这种情况,因为输入可能永远都不会是0。
  • 变体:参数化的ReLU(Parameterized ReLU,pReLU),允许即使参数是负的,某些信息依然可以通过,其定义如下: p R e L U ( x ) = m a x ( 0 , x ) + α m i n ( 0 , x ) \mathrm{pReLU}(x)=\mathrm{max}(0,x)+\alpha\mathrm{min}(0,x) pReLU(x)=max(0,x)+αmin(0,x)等等。

1.3.2. sigmoid函数

  • 将输入变换为区间(0, 1)上的输出。
  • 在隐藏层中已经较少使用, 它在大部分时候被更简单、更容易训练的ReLU所取代。
  • 定义: s i g m o i d ( x ) = 1 1 + e x p ( − x ) \mathrm{sigmoid}(x)=\frac{1}{1+\mathrm{exp}(-x)} sigmoid(x)=1+exp(x)1
    sigmoid
  • 导数: d d x s i g m o i d ( x ) = s i g m o i d ( x ) ( 1 − s i g m o i d ( x ) ) \frac{\mathrm{d}}{\mathrm{d}x}\mathrm{sigmoid}(x)=\mathrm{sigmoid}(x)(1-\mathrm{sigmoid}(x)) dxdsigmoid(x)=sigmoid(x)(1sigmoid(x))
    gradofsigmoid

1.3.3. tanh函数

  • 将其输入压缩转换到区间(-1, 1)上。
  • 定义: t a n h ( x ) = 1 − e x p ( − 2 x ) 1 + e x p ( − 2 x ) \mathrm{tanh}(x)=\frac{1-\mathrm{exp}(-2x)}{1+\mathrm{exp}(-2x)} tanh(x)=1+exp(2x)1exp(2x)
    tanh
  • 当输入接近0时,tanh函数接近线性变换。
  • 导数: d d x t a n h ( x ) = 1 − t a n h 2 ( x ) \frac{\mathrm{d}}{\mathrm{d}x}\mathrm{tanh}(x)=1-\mathrm{tanh}^2(x) dxdtanh(x)=1tanh2(x)
    gradoftanh

2. 代码实现

2.1. 主要代码

net = nn.Sequential(
        nn.Flatten(),
        nn.Linear(784, 256),
        nn.ReLU(),
        nn.Linear(256, 10)
    ).cuda()

2.2. 完整代码

import os
import torch
from torchvision import transforms
from torchvision.datasets import FashionMNIST
from torch.utils.data import DataLoader
from torch import nn
from tensorboardX import SummaryWriter
from rich.progress import track

def load_dataset():
    """加载数据集"""
    root = "./dataset"
    transform = transforms.Compose([transforms.ToTensor()])
    mnist_train = FashionMNIST(
        root=root, 
        train=True, 
        transform=transform, 
        download=True
    )
    mnist_test = FashionMNIST(
        root=root, 
        train=False, 
        transform=transform, 
        download=True
    )

    dataloader_train = DataLoader(
        mnist_train,
        batch_size, 
        shuffle=True,
        num_workers=num_workers
    )
    dataloader_test = DataLoader(
        mnist_test,
        batch_size, 
        shuffle=False,
        num_workers=num_workers
    )
    return dataloader_train, dataloader_test

class Accumulator:
    """在n个变量上累加"""
    def __init__(self, n):
        self.data = [0.0] * n

    def add(self, *args):
        self.data = [a + float(b) for a, b in zip(self.data, args)]

    def reset(self):
        self.data = [0.0] * len(self.data)

    def __getitem__(self, idx):
        return self.data[idx]
    
def accuracy(y_hat, y):
    """计算预测正确的数量"""
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        y_hat = y_hat.argmax(axis=1)
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())


if __name__ == "__main__":
    # 全局参数设置
    batch_size = 256
    num_epochs = 10
    num_workers = 3

    lr = 0.1
    device = torch.device('cuda:0')

    # 创建记录器
    def log_dir():
        root = "runs"
        if not os.path.exists(root):
            os.mkdir(root)
        order = len(os.listdir(root)) + 1
        return f'{root}/exp{order}'
    writer = SummaryWriter(log_dir=log_dir())

    # 加载数据集
    dataloader_train, dataloader_test = load_dataset()

    # 定义模型
    net = nn.Sequential(
        nn.Flatten(),
        nn.Linear(784, 256),
        nn.ReLU(),
        nn.Linear(256, 10)
    ).to(device)
    def init_weights(m):
        if type(m) == nn.Linear:
            nn.init.normal_(m.weight, mean=0, std=0.01)
            nn.init.constant_(m.bias, val=0)
    net.apply(init_weights)
    criterion = nn.CrossEntropyLoss(reduction='none')
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)

    train_metrics = Accumulator(3)  # 训练损失总和、训练准确度总和、样本数
    test_metrics = Accumulator(2)   # 测试准确度总和、样本数
    for epoch in track(range(num_epochs), description='多层感知机'):
        for X, y in dataloader_train:
            X, y = X.to(device), y.to(device)
            loss = criterion(net(X), y)
            optimizer.zero_grad()
            loss.mean().backward()
            optimizer.step()

        train_metrics.reset()
        for X, y in dataloader_train:
            X, y = X.to(device), y.to(device)
            y_hat = net(X)
            loss = criterion(y_hat, y)
            train_metrics.add(loss.sum(), accuracy(y_hat, y), y.numel())
        train_loss, train_acc = train_metrics[0]/train_metrics[2], train_metrics[1]/train_metrics[2]

        test_metrics.reset()
        with torch.no_grad():    
            for X, y in dataloader_test:
                X, y = X.to(device), y.to(device)
                y_hat = net(X)
                test_metrics.add(accuracy(y_hat, y), y.numel())
        test_acc = test_metrics[0] / test_metrics[1]
        writer.add_scalars("metrics", {
            'train_loss': train_loss, 
            'train_acc': train_acc, 
            'test_acc': test_acc
            }, epoch)
        
    writer.close()

2.2. 输出结果

多层感知机

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
多层感知机(Multilayer Perceptron,MLP)是一种深度学习模型,它是在单层神经网络的基础上添加了一个或多个隐藏层的神经网络。在PyTorch中,可以使用torch.nn模块来构建多层感知机模型。以下是构建一个简单的多层感知机模型的步骤: 1. 导入所需的库: ``` import torch from torch import nn ``` 2. 定义多层感知机模型类: ``` class MLP(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(MLP, self).__init__() self.fc1 = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU() self.fc2 = nn.Linear(hidden_size, output_size) def forward(self, x): x = self.fc1(x) x = self.relu(x) x = self.fc2(x) return x ``` 这个模型有一个输入层(input_size)、一个隐藏层(hidden_size)和一个输出层(output_size)。在模型的构造函数中,使用nn.Linear定义了两个全连接层,使用nn.ReLU作为激活函数。 3. 实例化模型: ``` input_size = 784 # 输入特征的大小 hidden_size = 128 # 隐藏层的大小 output_size = 10 # 输出的类别数 model = MLP(input_size, hidden_size, output_size) ``` 4. 定义损失函数和优化器: ``` criterion = nn.CrossEntropyLoss() # 分类任务常用的交叉熵损失函数 optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # 使用随机梯度下降优化器 ``` 5. 训练模型: ``` # 假设有训练数据集train_loader for images, labels in train_loader: # 将数据转换为模型所需的张量形式 images = images.view(-1, 28*28) labels = labels # 前向传播 outputs = model(images) # 计算损失 loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() ``` 以上是使用PyTorch实现多层感知机的基本步骤。根据具体的任务和数据集,你可以调整模型的结构、超参数和优化策略来提高模型性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值