用PyTorch实现一个卷积神经网络进行图像分类

用PyTorch实现一个卷积神经网络进行图像分类

原创 2017年07月18日 21:27:13

1. 回顾

在进入这一篇博客的内容之前,我们先确保已经成功安装好PyTorch,可以参考我之前的一篇博客“Ubuntu12.04下PyTorch详细安装记录”:

http://blog.csdn.net/wblgers1234/article/details/72902016
   
   
  • 1

接下来,我们用设计一个简单的卷积神经网络的方式来熟悉PyTorch的用法。

2. 设计卷积神经网络

在设计复杂的神经网络之前,我们依然考虑按照斯坦福大学的“UFLDL Tutorial”的CNN部分来构建一个简单的卷积神经网络,即按照以下的设计:

输入层->二维特征卷积->sigmoid激励->均值池化->全连接网络->softmax输出
   
   
  • 1

按照下面的代码对应来看神经网络的结构。注释得很清晰,有不清楚的可以留言,这里就不再赘述。

class CNN_net(nn.Module):
    def __init__(self):
        # 先运行nn.Module的初始化函数
        super(CNN_net, self).__init__()
        # 卷积层的定义,输入为1channel的灰度图,输出为4特征,每个卷积kernal为9*9
        self.conv = nn.Conv2d(1, 4, 9)
        # 均值池化
        self.pool = nn.AvgPool2d(2, 2)
        # 全连接后接softmax
        self.fc = nn.Linear(10*10*4, 10)
        self.softmax = nn.Softmax()

    def forward(self, x):
        # 卷积层,分别是二维卷积->sigmoid激励->池化
        out = self.conv(x)
        out = F.sigmoid(out)
        out = self.pool(out)
        print(out.size())
        # 将特征的维度进行变化(batchSize*filterDim*featureDim*featureDim->batchSize*flat_features)
        out = out.view(-1, self.num_flat_features(out))
        # 全连接层和softmax处理
        out = self.fc(out)
        out = self.softmax(out)
        return out
    def num_flat_features(self, x):
        # 四维特征,第一维是batchSize
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

3. 数据准备

还记得torchvision吗?我们在做和图像有关的实验时会更多地与它打交道。这次我们选择最简单也是最广为人知的MNIST数据库来训练和测试CNN。同时在torchvision中有一个torchvision.datasets,它为很多常用的图像数据库提供接口,其中就包括MNIST。

from torchvision.datasets import MNIST
   
   
  • 1

需要先下载MNIST,并且转换为PyTorch可以识别的数据格式:

# MNIST图像数据的转换函数
trans_img = transforms.Compose([
        transforms.ToTensor()
    ])

# 下载MNIST的训练集和测试集
trainset = MNIST('./MNIST', train=True, transform=trans_img, download=True)
testset = MNIST('./MNIST', train=False, transform=trans_img, download=True)
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我们查看transforms.ToTensor()的解释,将原本的二维图像格式转换为PyTorch的基本单位torch.FloatTensor。

Converts a PIL.Image or numpy.ndarray (H x W x C) in the range [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0].
   
   
  • 1

4. 训练和测试

4.1 训练数据集

从代码中可以清晰的看见“前向传播”,“反向传播”,optimizer的求解。

# 训练过程
for i in range(epoches):
    running_loss = 0.
    running_acc = 0.
    for (img, label) in trainloader:
        # 转换为Variable类型
        img = Variable(img)
        label = Variable(label)

        optimizer.zero_grad()

        # feedforward
        output = net(img)
        loss = criterian(output, label)
        # backward
        loss.backward()
        optimizer.step()

        # 记录当前的lost以及batchSize数据对应的分类准确数量
        running_loss += loss.data[0]
        _, predict = torch.max(output, 1)
        correct_num = (predict == label).sum()
        running_acc += correct_num.data[0]

    # 计算并打印训练的分类准确率
    running_loss /= len(trainset)
    running_acc /= len(trainset)

    print("[%d/%d] Loss: %.5f, Acc: %.2f" %(i+1, epoches, running_loss, 100*running_acc))
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在训练完成之后,有一个处理很重要,需要将当前的网络设置为“测试模式”,然后才可以进行测试集的验证。

# 将当前模型设置到测试模式
net.eval()
   
   
  • 1
  • 2
4.2 测试数据集

在测试过程中,只有“前向传播”过程对输入的图像进行分类预测。

# 测试过程
testloss = 0.
testacc = 0.
for (img, label) in testloader:
    # 转换为Variable类型
    img = Variable(img)
    label = Variable(label)

    # feedforward
    output = net(img)
    loss = criterian(output, label)

    # 记录当前的lost以及累加分类正确的样本数
    testloss += loss.data[0]
    _, predict = torch.max(output, 1)
    num_correct = (predict == label).sum()
    testacc += num_correct.data[0]

# 计算并打印测试集的分类准确率
testloss /= len(testset)
testacc /= len(testset)
print("Test: Loss: %.5f, Acc: %.2f %%" %(testloss, 100*testacc))
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
4.3 代码运行结果

从下面的结果,可以看到迭代10次的训练分类准确率和测试分类准确率:

CNN_net (
  (conv): Conv2d(1, 4, kernel_size=(9, 9), stride=(1, 1))
  (pool): AvgPool2d (
  )
  (fc): Linear (400 -> 10)
  (softmax): Softmax ()
)
[1/10] Loss: 1.78497, Acc: 68.79
[2/10] Loss: 1.54269, Acc: 93.10
[3/10] Loss: 1.52096, Acc: 94.93
[4/10] Loss: 1.51040, Acc: 95.82
[5/10] Loss: 1.50393, Acc: 96.45
[6/10] Loss: 1.49967, Acc: 96.77
[7/10] Loss: 1.49655, Acc: 97.02
[8/10] Loss: 1.49401, Acc: 97.24
[9/10] Loss: 1.49192, Acc: 97.45
[10/10] Loss: 1.49050, Acc: 97.56
Test: Loss: 1.48912, Acc: 97.62 %
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

该工程完整的代码我已经放到github上,有兴趣的可以去下载试试:

https://github.com/wblgers/stanford_dl_cnn/tree/master/PyTorch
   
   
  • 1
版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 2
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,我可以为您介绍如何使用PyTorch构建一个卷积神经网络进行手写数字图像分类。 和之前一样,您需要一个数据集来训练您的模型,可以使用MNIST数据集。首先,需要导入相关的库: ``` import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms ``` 接下来,定义一个卷积神经网络模型: ``` class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, kernel_size=3) self.conv2 = nn.Conv2d(32, 64, kernel_size=3) self.dropout1 = nn.Dropout2d(0.25) self.dropout2 = nn.Dropout2d(0.5) self.fc1 = nn.Linear(1600, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, 2) x = self.dropout1(x) x = torch.flatten(x, 1) x = F.relu(self.fc1(x)) x = self.dropout2(x) x = self.fc2(x) return F.log_softmax(x, dim=1) ``` 该模型包括两个卷积层和一个池化层,以及两个Dropout层和两个全连接层。其中,第一个全连接层的输入维度为1600,是因为前面的池化层和卷积层的输出维度为64x5x5=1600。 然后,您可以使用以下代码来定义优化器和损失函数: ``` model = Net() optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5) criterion = nn.CrossEntropyLoss() ``` 接下来,使用以下代码来加载数据集、训练和测试模型: ``` transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) train_dataset = datasets.MNIST('../data', train=True, download=True, transform=transform) test_dataset = datasets.MNIST('../data', train=False, transform=transform) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True) test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=True) epochs = 10 for epoch in range(1, epochs + 1): model.train() for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() if batch_idx % 100 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item())) model.eval() test_loss = 0 correct = 0 with torch.no_grad(): for data, target in test_loader: output = model(data) test_loss += criterion(output, target).item() pred = output.argmax(dim=1, keepdim=True) correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset))) ``` 在训练过程中,使用测试集来验证模型的性能。 希望这个简单的卷积神经网络模型能够帮助您进行手写数字图像分类任务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值