卷积神经网络与手写字体识别pytorch实现

1.反向传播:在神经网络训练过程中,反向传播算法就是带有链式法则的梯度下降法。

I--->H--->O==>L

z1   z2    z3     z4

上图表示一个简单的例子,输入层I,隐藏层H,输出层O,损失值L

我们假设输入为z1,经过隐藏层得到了z2,经过输出层得到z3,最后通过损失函数算出损失值z4,然后正向传播到此结束,接着进行反向传播(backpropagation alg),我们先定义一个\delta,不用考虑是什么东西,我们将上图的传播方式颠倒一下。

I<---H<---O<==L

\delta1   \delta2    \delta3    \delta4

我们将这个\delta设为\delta4=dL/dL作为L的输入,然后经过O得到\delta3,然后经过H得到\delta2,最后经过I得到\delta1,这里的经过其实是反向传播,在这个过程中利用z3和\delta3和链接H,O的权重矩阵W(H,O)可以求得梯度值,\partialL/\partialW(H,O),同理z2,\delta2得到\partialL/\partialW(I,H)。

从总体抽象上反向传播得流程大致如此。具体数学实现其他地方资料非常充足^^

2.卷积神经网络识别物体模仿人脑视觉机制,感光,提取边缘,提取形状,抽象概念。

3.卷积的话,其实是相关性计算,滑动窗口的滑动值叫stride,又称步长,滑动到边缘时停止,如果此时停止了,有些时候中间像素会参与多次卷积,因此我们需要往图像外填充一些像素,叫做填充,padding。

4.池化的话,通常是降低维度,过程比较简单,下采样。比如我们有个特征图是8*8,池化窗口是4*4,每4*4进行一次采样,就会得到2*2的池化特征图。通常池化特征有最大池化和平均池化,一个是取池化窗口在特征图内最大值作为池化特征图值,平均也同样。

下面我们来用pytorch实现一个MNIST手写数据库的识别。

import torch
from torchvision import datasets, transforms
from torch import nn, optim
import torch.nn.functional as F
import os

# 图像预处理
# 对数据进行标准化,先减去 mean(均值)再除以 std(标准差)。
# 在这里,(0.1307,) 是均值(mean)而 (0.3081,) 是标准差。
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

# 下载数据集
trainset = datasets.MNIST('data', train=True, download=True, transform=transform)
testset = datasets.MNIST('data', train=False, download=True, transform=transform)


# 构建一个LeNet
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        # 输入一张灰度图,输出6个特征图,第三个参数可以写为5,代表5*5的滤波器
        self.c1 = nn.Conv2d(1, 6, (5, 5))
        self.c3 = nn.Conv2d(6, 16, 5)
        # 全连接层,将16个特征图大小为4*4连接到120个点,4*4与mnist数据集有关
        self.fc1 = nn.Linear(16 * 4 * 4, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # c1卷积后,使用relu增加非线性拟合能力,然后池化,核为2*2
        x = F.max_pool2d(F.relu(self.c1(x)), 2)
        x = F.max_pool2d(F.relu(self.c3(x)), 2)
        # 将x转化为1维向量,num_flat_features计算特征点数
        x = x.view(-1, self.num_flat_features(x))
        # 全连接fc1,fc2,fc3
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        # 获取张量x除了第一个维度(通常是batch size)之外的所有维度大小,将其存储在名为size的列表中
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features


CUDA = torch.cuda.is_available()
if CUDA:
    lenet = LeNet().cuda()
else:
    lenet = LeNet()

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(lenet.parameters(), lr=1e-3, momentum=0.9)

# batch_size一次性加载的数据量,shuffle=True表示遍历不同批次的数据时打乱顺序,num_workers=2表示使用两个子进程加载数据
# 在windows中,num_workers 通常是0,可以避免问题
trainLoader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=0)


# 训练
def Train(model, criterion, optimizer, epochs=1):
    for epoch in range(epochs):
        running_loss = 0.0
        for i, data in enumerate(trainLoader, 0):
            inputs, labels = data
            if CUDA:
                inputs, labels = inputs.cuda(), labels.cuda()
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            # 调用优化器的step()方法来更新模型参数
            optimizer.step()

            running_loss += loss.item()
            if i%1000 == 999:
                print('[Epoch:%d, Batch:%5d] Loss: %.3f' % (epoch + 1, i + 1, running_loss / 1000))
                running_loss = 0.0

    print('finished')


# Train(lenet, criterion, optimizer, epochs = 2)


# 保存和加载
# torch.save(lenet, 'model.pkl')
# lenet = torch.load('model.pkl')
torch.save(lenet.state_dict(), 'model.pkl')
lenet.load_state_dict(torch.load('model.pkl'))

def load_param(model, path):
    if os.path.exists(path):
        model.load_state_dict(torch.load(path))

def save_param(model,path):
    torch.save(model.state_dict(),path)


# 测试集测试
testset = datasets.MNIST('data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False,num_workers=0)

def Test(testloader, model):
    correct = 0
    total = 0
    for data in testloader:
        images, labels = data
        if CUDA:
            images = images.cuda()
            labels = labels.cuda()
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
    print('Accuracy on the test set: %d %%' % (100 * correct / total))



load_param(lenet, 'model.pkl')
Train(lenet, criterion, optimizer, epochs = 2)
save_param(lenet,'model.pkl')
Test(testloader,lenet)





  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值