首页 > 其他分享 >多层全连接神经网络(八)---实现MNIST手写数字分类

多层全连接神经网络(八)---实现MNIST手写数字分类

时间:2024-07-26 08:59:56浏览次数:9  
标签:loss nn dim self --- 神经网络 hidden data MNIST

简单的三层全连接神经网络

        在 PyTorch 里面可以很简单地定义三层全连接神经网络。

class simpleNet(nn.Module):
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(simpleNet, self).__init__()
        self.layer1 = nn.Linear(in_dim, n_hidden_1)
        self.layer2 = nn.Linear(n_hidden_1, n_hidden_2)
        self.layer3 = nn.Linear(n_hidden_2, out_dim)

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x

        对于这个三层网络,需要传递进去的参数包括:输入的维度、第一层网络的神经元个数、第二层网络神经元的个数,以及第三层网络(输出层)神经元的个数。

添加激活函数

        接着改进一下网络,添加激活函数增加网络的非线性,方法也非常简单。

class Activation_Net(nn.Module):
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(Activation_Net, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Linear(in_dim, n_hidden_1), nn.ReLU(True)
        )
        self.layer2 = nn.Sequential(
            nn.Linear(n_hidden_1, n_hidden_2), nn.ReLU(True)
        )
        self.layer3 = nn.Sequential(
            nn.Linear(n_hidden_2, out_dim)
        )

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x

        这里只需要在每层网络的输出部分添加激活函数就可以了,用到 nn.sequential(),这个函数是将网络的层组合到一起,比如上面将 nn.Linear() 和 nn.ReLU() 组合到一起作为 self.layer。注意最后一层输出层不能添加激活函数,因为输出的结果表示的是实际的得分。

添加批标准化

        最后添加一个加快收敛速度的方法——批标准化。

class Batch_Net(nn.Module):
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(Batch_Net, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Linear(in_dim, n_hidden_1),
            nn.BatchNorm1d(n_hidden_1), nn.ReLU(True)
        )
        self.layer2 = nn.Sequential(
            nn.Linear(n_hidden_1, n_hidden_2),
            nn.BatchNorm1d(n_hidden_2), nn.ReLU(True)
        )
        self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x

        同样使用 nn.seguential() 将 nn.BatchNorm1d() 组合到网络层中,注意批标准化一般放在全连接层的后面、非线性层(激活函数)的前面。

训练网络

        网络的定义特别简单,现在用 MNIST 数据集训练网络并测试一下每种网络的结果。

        MNIST 数据集是一个手写字体数据集,包含 0 到 9 这10个数字,其中有55000张训练集,10000张测试集,5000张验证集,图片大小是28x28的灰度图,如图3.28所示。

        首先需要导入一些要用的包:

import torch
from torch import nn, optim
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

        然后可以定义一些超参数,如batch_size、learning_rate 还有 num_epoches等。

# 超参数 Hyperparameters
batch_size = 64
learning_rate = 1e-2
num_epoches = 20

        接着需要进行数据预处理,就像之前介绍的,需要将数据标准化,这里运用到的两数是torehvision.transforms,它提供了很多图片预处理的方法。这里使用两个方法:第一个是transforms.ToTensor(),第二个是 transforms.Normalize()。 

        transform.Torensor() 很好理解,就是将图片转换成 PyTorch 中处理的对象 Tensor 在转化的过程中 PyTorch自动将图片标准化了,也就是说 Tensor 的范围是0~1。接着我们使用 transforms.Normalize(),需要传入两个参数:第一个参数是均值,第二个参数是方差,做的处理就是减均值,再除以方差。

data_tf = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize([0.5], [0.5])]
)

        这里 transforms.Compose() 将各种预处理操作组合到一起,transforms.Normalize([0.5],[0.5]) 表示减去 0.5 再除以 0.5,这样将图片转化到了 -1 ~ 1 之间,注意因为图片是灰度图,所以只有一个通道,如果是彩色的图片,有三通道,那么用 transforms.Normalize([a,b,c],[d,e,f]) 来表示每个通道对应的均值和方差。 

        然后读取数据集。

# 下载训练集 MNISST 手写数字训练集
train_dataset = datasets.MNIST(root="./data", train=True, transform=data_tf, download=True)
test_dataset = datasets.MNIST(root="./data", train=False, transform=data_tf)

train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

        通过 PyTorch 的内置函数 torchvision.datasets.MNIST 导入数据集,传入数据预处理,前面介绍了如何定义自己的数据集,之后会用具体的例子说明。接着使用 torch.utils.data.DataLoader 建立一个数据迭代器,传入数据集和 batch_size,通过 shuffle=True 来表示每次迭代数据的时候是否将数据打乱。

        接着导入网络,定义损害函数和优化方法。

model = simpleNet(28 * 28, 300, 100, 10)
if torch.cuda.is_available():
    model.cuda()

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate)

         net.simpleNet 是定义的简单三层网络,里面的参数是28x28,300,100,10,其中输入的维度是 28x28,因为输入图片大小是28x28,然后定义两个隐藏层分别是 300 和 100,最后输出的结果必须是10,因为这是一个分类问题,一共有0~9这10个数字,所以是10分类。损失函数定义为分类问题中最常见的损失函数交叉熵,使用随机梯度下降来优化损失函数。

        接着开始训练网络。

for epoch in range(num_epoches):
    running_loss = 0.0
    correct = 0
    total = 0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data
        if torch.cuda.is_available():
            inputs, labels = inputs.cuda(), labels.cuda()
        optimizer.zero_grad()

        outputs = model(inputs.view(-1, 28 * 28))
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

    epoch_loss = running_loss / len(train_loader)
    epoch_acc = 100 * correct / total
    print('Epoch [{}/{}], Loss: {:.4f}, Accuracy: {:.2f}%'
        .format(epoch + 1, num_epoches, epoch_loss, epoch_acc))

        最后训练完网络之后需要测试网络,通过下面的代码来测试。

# eval
model.eval()
eval_loss = 0
eval_acc = 0
for data in test_loader:
    img, label = data
    img = img.view(img.size(0), -1)
    if torch.cuda.is_available():
        img = Variable(img).cuda()
        label = Variable(label).cuda()
    else:
        img = Variable(img)
        label = Variable(label)
    out = model(img)
    loss = criterion(out, label)
    eval_loss += loss.item() * label.size(0)
    _, pred = torch.max(out, 1)
    num_correct = (pred == label).sum()
    eval_acc += num_correct.item()

print('Test Loss: {:.6f}, ACC: {:.6f}'
    .format(eval_loss / (len(test_dataset)), eval_acc / (len(test_dataset))))

标签:loss,nn,dim,self,---,神经网络,hidden,data,MNIST
From: https://blog.csdn.net/miodi/article/details/140602563

相关文章

  • IEEE-Trans系列:TIV“倒下”,这本1区Top势头正猛,CCF-B类,国人友好,年发文1500!
    本周投稿推荐SCI&EI•1区计算机类,3.5-4.0(1个月录用)•CCF推荐,1区-Top(3天初审)EI•各领域沾边均可(2天录用)知网(CNKI)、谷歌学术•7天录用-检索(百发百中,包检索)SSCI• 1区,2.0-3.0(1个月录用)工程技术类2024年7月23日,著名顶级期刊IEEETransactionsonIntelligentVehi......
  • CSS样式--续写
    哥们上课听到啥写啥,不做无意义的笔记。---驴言一刻今天写常见的一些样式规划,例如字体的,页面的,浮动的这些。(都是css样式,不是标签)字体样式:这个是在页面编写中会经常用到的一类样式。例如字体的加粗、大小、变细、颜色变化、斜体、字体类型等等。字体加粗/变细:font-weight在c......
  • Python - 检测字母模式而不迭代所有可能的组合
    对于可能不太有用的标题,我表示歉意,我不知道如何将这个问题总结为一句话。我正在尝试计算Python3.10中一个单词有多少个“单位”长。一个“单位”是(C表示辅音,V表示元音)CV或VC或C或V(后两者仅在没有配对时使用)可以制作)。例如,“件”将为三个单位......
  • PYTHON 代码执行错误 - 冻结 importlib._bootstrap>(1165)_find_and_load()?
    在MACOS10.15(CATALINA)上执行此PYTHON代码时出现以下错误。我正在使用IDLEShell编写PYTHON3.11。Python3.11.4(v3.11.4:d2340ef257,Jun 62023,19:15:51)[Clang13.0.0(clang-1300.0.29.30)]ondarwinType"help","copyright","credits"o......
  • 像素值与 2D NPS 的标准差 - NPS 的总和还是平均值?
    我正在尝试根据Python中的2DNPS估计空间域中像素值的SD。我希望需要NPS值的总和除以像素总数。然而,我只能通过平均值除以像素总数来达到正确的估计。任何人都可以指出我为什么会这样吗?请参阅下面的代码示例。“SUM:“importnumpyasnpfromscipy.ff......
  • Azure Open AI - Python 和 Java API 之间 gpt4o 的结果截然不同
    我使用Java和PythonAPI对AzureOpenAI进行相同的调用,但收到截然不同的结果:相同的系统提示相同的用户提示适用于Java和Python的azureai包的相同(最新)版本尽管输入的用户和系统提示完全相同,但响应却非常不同-python提示是“正确的”并......
  • 使用 aws cdk 设置用户池客户端属性以具有读/写访问权限 - Python
    我试图根据属性给予一些自定义属性特定的读/写访问权限。我收到此错误。资源处理程序返回消息:“无效写入创建客户端时指定的属性(服务:CognitoIdentityProvider,状态代码:400,请求ID:<request_id>)”(RequestToken:<request_token>,HandlerErrorCode:InvalidRequest)任何人都可以为......
  • 试图找出此页面的逻辑:存储了大约 ++ 100 个结果 - 并使用 Python 和 BS4 进行了解析
    试图找出此页面背后的逻辑:我们已将一些结果存储在以下数据库中:https://www.raiffeisen.ch/rch/de/ueber-uns/raiffeisen-gruppe/Organization/raiffeisenbanken/deutsche-schweiz.html#accordionitem_18104049731620873397从a到z大约:120个结果或更多:......
  • Python (Pebble) - 超时功能。当 TimeoutError 发生时,获取从 iterable 传递给函数的值
    我正在尝试在Pebble中设置工作超时(基本上有效)frompebbleimportProcessPoolfrommultiprocessingimportProcess,Pool,cpu_countimporttimedeftest_fn(randomNumberFromList):#print(f'Beginngingforthisnumber:{randomNumberFromList}')ifr......
  • java基础-面向对象
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言Java一门面向对象编程语言。面向对象的特点:抽象、封装、继承、多态。一、抽象编程的目的就是将现实的事物抽象为计算机可以理解的代码。二、封装目的是将事物的信息放到一个类中表达,可以......