转:Pytorch模型小例子

本文介绍了如何在五分钟内使用PyTorch快速构建一个简单的卷积神经网络模型,用于KuzushijiMNIST数据集的图像分类。首先,导入数据并进行预处理,然后定义模型,接着编写训练循环并运行,最后进行验证集上的评估。模型包括两个卷积层,ReLU激活函数和最大池化操作,以及全连接层。在训练过程中,使用Adam优化器和交叉熵损失函数。验证集准确率达到95%。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接:五分钟内编写Pytorch模型

如果你想在五分钟内编写Pytorch模型,需要完成四个步骤:

  1. 导入和预处理(数据集)数据,并对其进行批处理(数据加载器)

  2. 使用神经网络建立模型。

  3. 编写一个训练循环并运行它。

  4. 验证集上的验证。

由于MNIST已经做得非常彻底,我们将介绍如何导入torchvision数据集,并在五分钟内编写一些代码。出于这个原因,它不会很漂亮,但会起作用。

1、下载和导入数据

因为MNIST已经做得很死了,我们将搜索标准的torchvision数据集,看看是否还有其他我们想要尝试和预测的东西。

让我们来看Kuzushiji MNIST,它是由70000张图像组成的MNIST数据集的平假名替代品。

首先,我们找到每个通道的平均值和标准偏差。这背后的原因是,我们希望对训练数据进行归一化,但Pytorch变换需要提前给出归一化平均值和标准偏差。因此,我们将使用数据集找到这些值,然后重新导入它,并用预定义的值传递一个归一化转换。

from torchvision import datasets
from torchvision import transforms
# 指定数据集路径为data,如果数据集不存在则进行下载
# 通过train=False获取测试集
data_path = "data/"
kmnist = datasets.KMNIST(data_path, train=True, download=True,
                         transform=transforms.Compose([
                             transforms.ToTensor()]))

kmnist_val = datasets.KMNIST(data_path, train=False, download=True,
                             transform=transforms.ToTensor())

上述代码的Kuzushiji MNIST数据会自动下载,结果如下:

请注意,kmnist是一个数据集,因此循环它会为我们提供每一个图像和每一个标签。因此,如果我们在数据集中的每个图像上循环,并沿着额外的第四维叠加它们,我们将得到所有图像的张量。

# t.stack:扩维堆叠
imgs = torch.stack([img_t for img_t, _ in kmnist], dim=3)

print(f"imgs.shape: {imgs.shape}")
# torch.Size([1, 28, 28, 60000])

现在我们计算每个通道的平均值。请注意,调用imgs.view(1,-1)将把所有的张量压缩到第二维度。我们在这个第二维度上取像素值的平均值(因此dim=1)和标准差。

# compute mean and std per channel
mean = imgs.view(1, -1).mean(dim=1)
std = imgs.view(1, -1).std(dim=1)
print(f"mean:{mean},std:{std}")
# mean:tensor([0.1918]),std:tensor([0.3483])

我们现在可以重新导入数据,使用Normalize转换以及将数组转换为张量。请注意,Normalize将像素值的平均值和标准偏差作为参数。

# 我们现在可以重新导入数据,使用Normalize转换以及将数组转换为张量。
# 请注意,Normalize将像素值的平均值和标准偏差作为参数。
# normalised data
t_kmnist = datasets.KMNIST(data_path, train=True, download=False,
                           transform=transforms.Compose([
                               transforms.ToTensor(),
                               # transforms.Normalize(0.1307,0.3081),
                               transforms.Normalize(mean, std)
                           ]))

t_kmnist_val = datasets.KMNIST(data_path, train=False, download=False,
                               transform=transforms.Compose([
                                   transforms.ToTensor()]))

现在我们有了数据集,我们需要将这些数据输入数据加载器进行批处理。如果你使用的是CPU,请确保设置较小的批处理大小,并将num_workers=1(这是一个GPU问题,不要太担心)。

# 数据加载器
train_loader = torch.utils.data.DataLoader(kmnist, batch_size=128,
                                           shuffle=True,
                                           num_workers=1)

val_loader = torch.utils.data.DataLoader(kmnist_val, batch_size=128,
                                         shuffle=False,
                                         num_workers=1)

我们可以从数据集中查看一些样本。

# 遍历
figure = plt.figure(figsize=(10, 8))

cols, rows = 5, 5

for i in range(1, cols * rows + 1):
    # randint返回tensor,size=(1,)一维一列,item返回数值
    sample_idx = torch.randint(len(t_kmnist), size=(1,)).item()
    img, label = t_kmnist[sample_idx]
    figure.add_subplot(rows, cols, i)

    plt.title(label)

    plt.axis("off")

    plt.imshow(img.squeeze(), cmap="gray")

plt.show()

构建模型

这不是一篇关于如何从理论上构建深度学习模型的教程。因此,我们将在这里介绍模型实现。

首先,需要将模型实例化为nn.Module的实例。其次,你需要使用常用的Python方法初始化类。最后,你需要一个模型初始化,在这里我们定义了所有的模型层,然后是一个forward方法,在这里我们告诉模型如何获取输入并将其传递给这些层。


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5,
                               stride=1, padding=2)
        self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1,
                               padding=2)
        self.layer1 = nn.Sequential(self.conv1, nn.ReLU(), nn.MaxPool2d(kernel_size=2))
        self.layer2 = nn.Sequential(self.conv2, nn.ReLU(), nn.MaxPool2d(kernel_size=2))
        self.out = nn.Linear(32 * 7 * 7, 10)  # output 10 classes

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        # flatten the output of conv2 to (batch_size, 32*7*7)
        x = x.view(x.size(0), -1)
        output = self.out(x)
        return output

在这个阶段,通过从dataloader中给出一个示例来调试模型总是很重要的。然后,我们将该图像传递给模型,并检查它是否输出了正确大小的内容。

img, _ = next(iter(train_loader))

img = img[0]

model = Net()

model(img.unsqueeze(0)).shape

>>> torch.Size([1, 10])

完美的我们构建了一个模型,该模型采用K-MNIST图像,并输出10个类,代表每个可能的数字0到9的10种不同概率。

编写和运行训练循环

像往常一样,我们的训练步骤是相似的。前向传播,计算损失,重置梯度(Pytorch)。反向传播以计算有关损失的梯度。用这些梯度更新我们的权重。

def training_loop(n_epochs, model, loss_fn, optimiser, train_loader):
    
    model.train()
    
    total_step = len(train_loader)
    
    for n in range(1, n_epochs+1):
        
        for i, (imgs, labels) in enumerate(train_loader):
            
            output = model(Variable(imgs)) # forward pass
            
            loss = loss_fn(output, Variable(labels)) # compute loss
            
            optimiser.zero_grad() # reset gradients
            
            loss.backward() # backpropagation
            
            optimiser.step() # update the weights
            
            if (i+1) % (n_epochs/10) == 0:
                
                print ('{} Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}' 
                       .format(datetime.datetime.now(), n, n_epochs, 
                               i + 1, total_step, loss.item()))

然后,我们实例化我们的模型,设置Adam优化器,并使用交叉熵损失(因为这是一个多类分类问题)。

 

model = Net()

optimiser = torch.optim.Adam(model.parameters(), lr=1e-2)

loss_fn = nn.CrossEntropyLoss()

然后把这些参数传递给训练循环。

 

training_loop(
    
    n_epochs = 10,
    
    model = model,
    
    loss_fn = loss_fn,
    
    optimiser = optimiser,
    
    train_loader = train_loader
)

验证模型

迭代验证数据加载器中的图像和标签,前向传播,通过在输出张量中找到值最高的索引(记住,我们输出了10个概率的向量)得到预测。data.squeeze()以获取实际的标量本身。最后,统计预测值与标签相等的样本数量,除以标签总数。

 

def validate(model, train_loader, val_loader):       
    
    model.eval() # set to eval mode to avoid batchnorm
    
    with torch.no_grad(): # avoid calculating gradients
        
        correct, total = 0, 0
        
        for images, labels in val_loader:
            
            test_output = model(images)
            
            pred_y = torch.max(test_output, 1)[1].data.squeeze()
            
            accuracy = (pred_y == labels).sum().item() / float(labels.size(0))
            
    print('VALIDATION SET ACCURACY: %.2f' % accuracy)
    
validate(model, train_loader, val_loader)

>>> VALIDATION SET ACCURACY: 0.95

验证集准确率为95%。

结论

让模型变得更好:

  • 在模型训练时打印验证集指标:显然,很高兴看到训练损失随着每个epoch而减少。但是,直到我们在训练后对模型进行验证,我们才真正了解模型的性能。如果在运行过程中打印验证准确性,你将更好地了解模型的成功。

  • 早停:一旦验证的准确性在一定时期内(称为耐心)没有提高,就回到表现最好的epoch并使用这些权重。

  • 看看其他指标:例如曲线下面积(AUC)。

  • 实现其他网络架构:自CNN引入以来,计算机视觉已经取得了长足的进步。你可以尝试其他体系结构来提高性能。

源码Kuzushiji.py如下:

import datetime

from matplotlib import pyplot as plt
from torch import nn
from torch.autograd import Variable
from torchvision import datasets
from torchvision import transforms
import torch


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5,
                               stride=1, padding=2)
        self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1,
                               padding=2)
        self.layer1 = nn.Sequential(self.conv1, nn.ReLU(), nn.MaxPool2d(kernel_size=2))
        self.layer2 = nn.Sequential(self.conv2, nn.ReLU(), nn.MaxPool2d(kernel_size=2))
        self.out = nn.Linear(32 * 7 * 7, 10)  # output 10 classes

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        # flatten the output of conv2 to (batch_size, 32*7*7)
        x = x.view(x.size(0), -1)
        output = self.out(x)
        return output


# 指定数据集路径为data,如果数据集不存在则进行下载
# 通过train=False获取测试集
data_path = "data/"
kmnist = datasets.KMNIST(data_path, train=True, download=True,
                         transform=transforms.Compose([
                             transforms.ToTensor()]))

kmnist_val = datasets.KMNIST(data_path, train=False, download=True,
                             transform=transforms.ToTensor())
# t.stack:扩维堆叠
imgs = torch.stack([img_t for img_t, _ in kmnist], dim=3)

print('Running3', __name__)
print(f"imgs.shape: {imgs.shape}")
# torch.Size([1, 28, 28, 60000])

# compute mean and std per channel
mean = imgs.view(1, -1).mean(dim=1)
std = imgs.view(1, -1).std(dim=1)
print(f"mean:{mean},std:{std}")
# mean:tensor([0.1918]),std:tensor([0.3483])

# 我们现在可以重新导入数据,使用Normalize转换以及将数组转换为张量。
# 请注意,Normalize将像素值的平均值和标准偏差作为参数。
# normalised data
t_kmnist = datasets.KMNIST(data_path, train=True, download=False,
                           transform=transforms.Compose([
                               transforms.ToTensor(),
                               # transforms.Normalize(0.1307,0.3081),
                               transforms.Normalize(mean, std)
                           ]))

t_kmnist_val = datasets.KMNIST(data_path, train=False, download=False,
                               transform=transforms.Compose([
                                   transforms.ToTensor()]))

# # 遍历 查看样本
# # figure = plt.figure(3,figsize=(10, 8))
# figure = plt.figure(6, None, None, '#FFD700', '#FF0000')
# plt.title("figure32")
# cols, rows = 5, 5
#
# for i in range(1, cols * rows + 1):
#     # randint返回tensor,size=(1,)一维一列,item返回数值
#     # sample_idx = torch.randint(low = 0,len(t_kmnist), size=(1,)).item()
#     sample_idx = torch.randint(len(t_kmnist), size=(1,)).item()
#     img, label = t_kmnist[sample_idx]
#     figure.add_subplot(rows, cols, i)
#
#     plt.title(label)
#
#     plt.axis("off")
#
#     plt.imshow(img.squeeze(), cmap="gray")
#
#  plt.show()

print('Running1', __name__)
# 数据加载器
train_loader = torch.utils.data.DataLoader(kmnist, batch_size=128,
                                           shuffle=True,
                                           num_workers=0)

val_loader = torch.utils.data.DataLoader(kmnist_val, batch_size=128,
                                         shuffle=False,
                                         num_workers=0)


# 从dataloader中给出一个示例来调试模型
# imgText, _ = next(iter(train_loader))
# imgT = imgText[0]
# model = Net()
# kll = model(imgT.unsqueeze(0)).shape
# print('Running2', __name__)
# print ("__name__:",__name__)
# print(f"img[0].shape: {kll}")
# # torch.Size([1, 28, 28, 60000])

def training_loop(n_epochs, model, loss_fn, optimiser, train_loader):
    model.train()

    total_step = len(train_loader)
    print('start Running1', __name__)
    for n in range(1, n_epochs + 1):

        for i, (imgs, labels) in enumerate(train_loader):

            output = model(Variable(imgs))  # forward pass

            loss = loss_fn(output, Variable(labels))  # compute loss

            optimiser.zero_grad()  # reset gradients

            loss.backward()  # backpropagation

            optimiser.step()  # update the weights

            if (i + 1) % (n_epochs / 10) == 0:
                print('{} Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
                      .format(datetime.datetime.now(), n, n_epochs,
                              i + 1, total_step, loss.item()))


def validate(model, train_loader, val_loader):
    model.eval()  # set to eval mode to avoid batchnorm

    with torch.no_grad():  # avoid calculating gradients
        correct, total = 0, 0
        for images, labels in val_loader:
            test_output = model(images)
            pred_y = torch.max(test_output, 1)[1].data.squeeze()
            accuracy = (pred_y == labels).sum().item() / float(labels.size(0))

    print('VALIDATION SET ACCURACY: %.2f' % accuracy)

if __name__ == '__main__':
    # 实例化模型
    model = Net()
    # 设置Adam优化器
    optimiser = torch.optim.Adam(model.parameters(), lr=1e-2)
    # 设置交叉熵损失(因为这是一个多类分类问题)
    loss_fn = nn.CrossEntropyLoss()
    # 训练循环
    training_loop(
        n_epochs=10,
        model=model,
        loss_fn=loss_fn,
        optimiser=optimiser,
        train_loader=train_loader
    )
    # 验证模型
    # validate(model, train_loader, val_loader)

### 回答1: CentOS 7启动httpd服务失败可能有多种原因,以下是一些常见的解决方法: 1. 检查httpd配置文件是否正确:可以使用命令`httpd -t`检查httpd配置文件是否正确,如果有错误,需要修改配置文件。 2. 检查端口是否被占用:可以使用命令`netstat -tlnp`查看端口是否被占用,如果被占用需要释放端口或修改httpd配置文件中的端口号。 3. 检查httpd服务是否安装:可以使用命令`rpm -qa | grep httpd`查看httpd服务是否安装,如果没有安装需要先安装httpd服务。 4. 检查httpd服务是否启动:可以使用命令`systemctl status httpd`查看httpd服务是否启动,如果没有启动需要使用命令`systemctl start httpd`启动httpd服务。 5. 检查SELinux是否开启:如果SELinux开启,可能会导致httpd服务启动失败,需要使用命令`setenforce 0`关闭SELinux,或者修改SELinux策略。 以上是一些常见的解决方法,如果以上方法都无法解决问题,可以查看httpd服务日志文件,找到具体的错误信息,然后根据错误信息进行解决。 ### 回答2: CentOS 7上的httpd服务启动失败可能有多种原因。以下列出了一些常见问题和解决方法: 1. 端口被占用 当httpd试图占用已被其他程序占用的端口时会启动失败。此时可以通过使用`netstat -tunlp`命令检查端口占用情况,然后杀死占用该端口的进程及时释放端口。或者修改httpd的配置文件,将端口修改为未被占用的端口。 2. 配置文件错误 有时httpd服务的配置文件中可能出现错误,例如语法错误或路径错误等等。在启动httpd服务之前,可以使用`apachectl configtest`命令进行检查,如果输出“Syntax OK”,则表示配置文件没有错误。如果出现错误,则需要根据错误提示进行相应修改。 3. 依赖关系问题 如果httpd依赖的其他程序或库缺失,也会导致启动失败。可以通过使用`systemctl status httpd.service`命令来查看httpd服务状态,如果输出“Failed to start”或“Loaded: failed”,则需要检查依赖关系是否完整。 4. SELinux问题 当SELinux启用时,有时会导致httpd服务启动失败。在这种情况下,可以在SELinux上禁用httpd服务,或者修改httpd配置文件解决SELinux相关的问题。 5. 用户权限问题 httpd服务启动可能需要特定的用户权限。如果使用的用户权限不够,则无法启动。可以尝试使用root用户启动httpd服务,或者根据需要修改相应的用户权限。 ### 回答3: CentOS 7中的Apache HTTP服务器(httpd)是一个常见的Web服务器,如果遇到httpd服务启动失败的情况,可能会影响服务器正常的工作和对外服务的稳定性。本文将提供一些可能会导致httpd服务启动失败的原因,并给出相应的解决方法。 1. 端口被占用 如果端口被其他进程占用,httpd服务就无法启动。可以通过 netstat -tulpn 命令查看端口占用情况,并杀死占用该端口的进程。如果端口被 httpd 服务自身占用,可以通过 systemctl restart httpd 命令重启 httpd 服务;如果是其他进程占用了端口,可以通过 kill 命令杀死该进程或更改 httpd.conf 文件配置,将 httpd 服务的端口改为其他空闲端口,重新启动。 2. 配置文件错误 httpd 服务的配置文件通常是 /etc/httpd/conf/httpd.conf,如果其中存在语法错误、权限问题或者其它配置错误,可能会导致 httpd 服务启动出错。可以通过将 httpd.conf 文件备份后删掉,重新执行 yum install httpd 命令安装 httpd 服务,然后手动修改 httpd.conf 文件,逐个检查每个配置项是否正确,确认无误后重启 httpd 服务。 3. SELinux 问题 SELinux 是 CentOS 7中提供的一种安全模块,它可以对系统文件和应用程序进行安全管控。如果 SELinux 配置不正确,可能会阻止 httpd 服务正常启动。可以通过修改 /etc/selinux/config 文件中 SELINUX=disabled 来暂时关闭 SELinux,然后重新启动 httpd 服务;或者一个更优的方式是,根据日志确定问题原因,使用命令 semanage 或者 setsebool 等工具将相关目录或者配置加入到 SELinux 许可列表中,重新启动 httpd 服务,以恢复服务正常工作。 4. 防火墙问题 如果你的 CentOs 7 服务器启用了防火墙,有可能会导致 httpd 服务启动失败。可以通过检查防火墙相关配置来确定问题原因,解决方案是修改防火墙规则,将端口 80 或者 443 等 httpd 服务需要的端口放行,重新启动 httpd 服务。 总之,当遇到 httpd 服务启动失败时,不要慌张,可以先通过日志或者执行命令查看错误信息,找到错误原因,然后根据错误原因一步一步解决问题。在解决问题过程中注意备份原始配置文件,以免造成不必要的损失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值