pytorch 多层感知机实现

27 篇文章 8 订阅
20 篇文章 1 订阅


一、前言

  1. 多层感知机通过 隐藏层 + 非线性激活函数 的方式来得到非线性模型,解决了感知机不能处理XOR分类的问题,多层感知机理论上可以拟合任何一种函数
  2. 常用的非线性激活函数是 Sigmoid、Tanh、Relu
  3. 输出层接Softmax用来处理多分类问题
  4. 超参数为隐藏层的个数和各个隐藏层的大小
    在这里插入图片描述

二、实现

import torch
from torch import nn
from d2l import torch as d2l
import torchvision
from torch.utils import data
from torchvision import transforms


# 构造数据集迭代器 -----------------------------------------
def load_data_fashion_mnist(batch_size, resize=None):
    """
    下载mnist数据集到指定目录,按批次加载到内存并返回迭代器
    :param batch_size:  # 每批次加载的数据量
    :param resize:      # 放大或缩小图片
    :return:
    """
    # 图片预处理方法定义
    trans = [transforms.ToTensor()]
    if resize:
        trans.insert(0, transforms.Resize(resize))
    # # transforms.Compose([
    #   transforms.Resize(resize),  # 改变图像大小
    #   transforms.ToTensor()       # 转为tensor张量,通过ToTensor实例将图像数从PIL类型变换成32位浮点数格式,并除以255使得所有图像的数值都在0到1之间
    # ])
    trans = transforms.Compose(trans)

    # 加载数据
    # root=r'./data', download=True 下载数据并缓存在./data目录
    # train=True  加载训练集
    # train=False 加载测试集
    mnist_train = torchvision.datasets.FashionMNIST(
        root=r'../data',
        train=True,
        transform=trans,
        download=True
    )
    mnist_test = torchvision.datasets.FashionMNIST(
        root=r'../data',
        train=False,
        transform=trans,
        download=True
    )

    # 返回训练集和测试集的迭代器
    # shuffle 是否乱序
    # num_workers 多进程提高图片从硬盘加载的速度
    train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True)
    test_iter = data.DataLoader(mnist_test, batch_size, shuffle=False)
    return (train_iter, test_iter)


# 初始化超参数 ---------------------------------
def init_weights(m):
    # 遍历 Sequential 如果发现 Linear 层,就把该层所有超参数初始化为均值0方差0.01的值
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)


# 评估准确率的方法 ----------------------------------------
# 定义预测准确率函数
def accuracy(y_hat, y):
    '''
    :param y_hat: 接收二维张量,例如 torch.tensor([[1], [0]...])
    :param y: 接收二维张量,例如 torch.tensor([[0.1, 0.2, 0.7], [0.8, 0.1, 0.1]...]) 三分类问题
    :return:
    '''
    # if len(y_hat.shape) > 1 and len(y.shape) > 1:
    y_hat = y_hat.argmax(axis=1)
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())

class Accumulator():
    ''' 对评估的正确数量和总数进行累加 '''
    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, item):
        return self.data[item]

# 对任意模型评估准确率的方法
def evaluate_accuracy(net, data_iter):
    ''' 计算在指定数据集上的模型精度 '''
    if isinstance(net, torch.nn.Module):
        net.eval()      # 将模型设置为评估模式
    metric = Accumulator(2)
    for X, y in data_iter:
        metric.add(accuracy(net(X), y), y.numel())
    return metric[0] / metric[1]

# 定义训练时的辅助动画
from IPython import display
class Animator():  #@save
    """在动画中绘制数据"""
    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
                 ylim=None, xscale='linear', yscale='linear',
                 fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
                 figsize=(3.5, 2.5)):
        # 增量地绘制多条线
        if legend is None:
            legend = []
        d2l.use_svg_display()
        self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使用lambda函数捕获参数
        self.config_axes = lambda: d2l.set_axes(
            self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts

    def add(self, x, y):
        # 向图表中添加多个数据点
        if not hasattr(y, "__len__"):
            y = [y]
        n = len(y)
        if not hasattr(x, "__len__"):
            x = [x] * n
        if not self.X:
            self.X = [[] for _ in range(n)]
        if not self.Y:
            self.Y = [[] for _ in range(n)]
        for i, (a, b) in enumerate(zip(x, y)):
            if a is not None and b is not None:
                self.X[i].append(a)
                self.Y[i].append(b)
        self.axes[0].cla()
        for x, y, fmt in zip(self.X, self.Y, self.fmts):
            self.axes[0].plot(x, y, fmt)
        self.config_axes()
        display.display(self.fig)
        d2l.plt.draw()
        d2l.plt.pause(0.001)
        display.clear_output(wait=True)


# 训练 -------------------------------------------------
# 定义每批次训练函数
def train_epoch_ch3(net, train_iter, loss, updater):
    # 判断是不是pytorch的model,如果是,就打开训练模式,pytorch的训练模式默认开启梯度更新
    if isinstance(net, torch.nn.Module):
        net.train()
    # 创建样本累加器【累加每批次的损失值、样本预测正确的个数、样本总数】
    metric = Accumulator(3)
    for X, y in train_iter:
        # 前向传播获得预测结果
        y_hat = net(X)
        # 计算损失值
        l = loss(y_hat, y)
        # 判断是pytorch自带的方法还是我们手写的方法【根据不同的方法有不同的处理方式】
        if isinstance(updater, torch.optim.Optimizer):
            # 梯度清零
            updater.zero_grad()
            # 损失值求和,反向传播【pytorch自动进行了损失值求和】
            l.backward()
            # 更新梯度
            updater.step()
            # 累加各参数
            metric.add(
                float(l)*len(y),        # 损失值总数
                accuracy(y_hat, y),     # 样本预测正确的总数
                y.size().numel()        # 样本总数
            )
        else:
            # 损失值求和,反向传播
            l.sum().backward()
            # 梯度更新
            updater(X.shape[0])
            # 累加各参数
            metric.add(float(l.sum()), accuracy(y_hat, y), y.size().numel())
    # 返回 平均损失值 和 预测正确的概率
    # print("metric[0]: {}".format(metric[0]))
    # print("metric[1]: {}".format(metric[1]))
    # print("metric[2]: {}".format(metric[2]))
    return metric[0]/metric[2], metric[1]/metric[2]

# 定义训练方法
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):
    """训练模型 """
    # 初始化训练动画
    animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],
                        legend=['train loss', 'train acc', 'test acc'])
    # 训练 num_epochs 代
    for epoch in range(num_epochs):
        # 调用训练方法
        # 返回  平均损失值 和 预测正确的概率
        train_metrics = train_epoch_ch3(net, train_iter, loss, updater)
        # 测试集上的准确率
        test_acc = evaluate_accuracy(net, test_iter)
        # 绘制【训练代数,平均损失值、前向传播时的预测正确率、测试集预测正确率】
        animator.add(epoch + 1, train_metrics + (test_acc,))


if __name__ == '__main__':

    # 定义网络 ----------------------------------------
    net = nn.Sequential(
        nn.Flatten(),           # 1*28*28 拉直成一维 784
        nn.Linear(784, 256),	# 输入784维输出256维
        nn.ReLU(),				# relu激活
        nn.Linear(256, 10)		# 输入256维输出10维,损失函数 CrossEntropyLoss 自带 softmax,因此这里不需要 softmax
    )

    # 初始化超参数 ------------
    net.apply(init_weights)

    # 定义损失函数 ----------------
    loss = nn.CrossEntropyLoss()	

    # 定义优化算法【SGD】----------------------------------
    updater = torch.optim.SGD(net.parameters(), lr=0.1)

    # 开始训练 ------------------------------------------------------------------------------
    num_epochs, batch_size = 10, 256                                # 训练代数及每批次送入样本数
    train_iter, test_iter = load_data_fashion_mnist(batch_size)     # 获得数据迭代器
    print(evaluate_accuracy(net, test_iter))
    # 使用随机初始化的net预测十分类测试,正确率刚好在10%左右
    # 0.1149
    train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)
    
  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
多层感知(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实现多层感知的基本步骤。根据具体的任务和数据集,你可以调整模型的结构、超参数和优化策略来提高模型性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

什么都干的派森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值