山野莽夫

  • 归档
    • 随笔
    • 建站资源
    • 分享
    • 代码
  • 地球物理学
    • 专业课
    • 概念解释
  • 计算机
  • 互联网
  • 教程
  • 规划
  • 实验室
    • 珍藏的软件
    • 贴吧云签到
    • A1账号自助申请
山野莽夫
小学生的挣扎的点点滴滴
  1. 首页
  2. 代码
  3. 正文

人工智能深度学习之卷积神经网络CNN LeNet-5网络 Pytorch 详细代码

2020年2月19日 3727点热度 3人点赞 1条评论

卷积神经网络是真正的可以算得上是深度学习网络的神经网络了。毕竟传统的BP算法,不能算是真的深度学习算法。对于卷积神经网络来说,最具有代表性的网络就是Lenet5网络了。所以学习卷积神经网络,一般从Lenet5学起。对于这种复杂的网络我们完全没有必要,使用python一点一点写。有很多现成的框架我们可以使用。比如Tensorflow和Pytorch。但是Pytorch更好学习一点,于是我就是用Pytorch尝试着写了这个代码,来尝试学习卷积神经网络。

对于卷积神经网络,网上有很多资料,我完全没有必要重复造轮子。我只放一个链接吧。

https://blog.csdn.net/weixin_42398658/article/details/84392845

这儿介绍的很清楚。

一、Lenet5网络模型图

二、Lenet5详细分析

1. C1层-卷积层

输入:1*32*32(输入特征图数和大小)

卷积核:6*5*5(卷积核个数和卷积核大小)

输出:6*28*28(输出特征图数和大小)

2.S2层-池化层(下采样层)

输入:6*28*28(输入特征图数和大小)

采样区域:2*2

输出:6*14*14(输出特征图数和大小)

采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果套上sigmoid 等函数

3.C3-卷积层

输入:6*14*14 不同方式组合

卷积核:16*5*5(卷积核个数和卷积核大小)

输出:16*10*10

4.S4层-池化层(下采样层)

输入:16*10*10(输入特征图数和大小)

采样区域:2*2

输出:16*5*5(输出特征图数和大小)

采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果套上sigmoid 等函数

5.C5-卷积层(相当于与S4全连接)

输入:16*5*5

卷积核:120*5*5(卷积核个数和卷积核大小)

输出:120*1*1

6.F6层-全连接层

输入:120*1

激活函数:sigmod

输出:84*1

7.Output层-全连接层

输入:84*1

输出:10*1

输出层由欧式径向基函数(Euclidean Radial Basis Function)单元组成,每类一个单元,每个有84个输入。换句话说,每个输出RBF单元计算输入向量和参数向量之间的欧式距离。输入离参数向量越远,RBF输出的越大。

三、模型实现

学习神经网络主要是学习神经网络的原理,所以没有必要完全复现这个完整的Lenet5。网上很多代码都是低级api,就是自己写模型类。但是我感觉 torch.nn.Sequential 这个类很强大,于是就想写了如下的模型,使用pytorch高级api搭建Lenet5。C5卷积层被视为与S4层全连接。所以S4层输出之后把结果变成400*1的向量。然后与400个输入84个输出的C5线性层全连接。另外未实现池化层S2、S4的sigmod池化,使用平均值池化代替。

激活函数使用性能更加优秀的ReLu激活函数。网络最后一层为高斯连接层。而我们为了简单起见还是用了全连接层。模型如下:

model = nn.Sequential(
    # C1
    nn.Conv2d(1, 6, (5, 5), 1, 2),
    nn.ReLU(),
    # S2
    nn.AvgPool2d((2, 2)),
    # C3
    nn.Conv2d(6, 16, (5, 5), 1),
    nn.ReLU(),
    # S4
    nn.AvgPool2d((2, 2)),
    # C5
    Flatten(),
    nn.Linear(5*5*16, 120),
    nn.ReLU(),
    # F6
    nn.Linear(120, 84),
    nn.ReLU(),
    # OUTPUT
    nn.Linear(84, 10),
)

四、数据集描述

MNIST 数据集来自美国国家标准与技术研究所, National Institute of Standards and Technology (NIST). 训练集 (training set) 由来自 250 个不同人手写的数字构成, 其中 50% 是高中学生, 50% 来自人口普查局 (the Census Bureau) 的工作人员. 测试集(test set) 也是同样比例的手写数字数据.

MNIST数据集分为训练集和测试集。训练数据集包含 60,000 个样本, 测试数据集包含 10,000 样本. 在 MNIST 数据集中的每张图片由 28 x 28 个像素点构成, 每个像素点用一个灰度值表示. 

五、详细代码

import torch
from torch import nn, optim
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
import numpy as np
#from logger import Logger

# 定义超参数
batch_size = 128        # 批的大小
learning_rate = 0.001     # 学习率
num_epoches = 20000        # 遍历训练集的次数


# 下载训练集 MNIST 手写数字训练集
train_dataset = datasets.MNIST(
    root='./data', train=True, transform=transforms.ToTensor(), download=True)

test_dataset = datasets.MNIST(
    root='./data', train=False, transform=transforms.ToTensor())

# 数据集分批
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)


# 多维向量归一化400*1一维向量
class Flatten(nn.Module):
    def forward(self, input):
        return input.reshape(input.size(0), -1)


# 模型定义
model = nn.Sequential(
    # C1
    nn.Conv2d(1, 6, (5, 5), 1, 2),
    nn.ReLU(),
    # S2
    nn.AvgPool2d((2, 2)),
    # C3
    nn.Conv2d(6, 16, (5, 5), 1),
    nn.ReLU(),
    # S4
    nn.AvgPool2d((2, 2)),
    # C5 # 多维向量归一化400*1一维向量
    Flatten(),
    nn.Linear(5*5*16, 120),
    # nn.Conv2d(16, 120, (5, 5), 1),
    nn.ReLU(),
    # nn.BatchNorm1d(120),# 批量准化
    # nn.Dropout(),
    # F6

    nn.Linear(120, 84),
    nn.ReLU(),
    # nn.BatchNorm1d(84),
    # nn.ReLU(),
    # OUTPUT
    # nn.Dropout(),
    nn.Linear(84, 10),
    # nn.Softmax(dim=1),

)


# 定义loss和optimizer
# 交叉熵损失函数
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate) # 优化器代替手动优化使用Adam 优化方法

# 开始训练
for epoch in range(num_epoches):
    print('epoch {}'.format(epoch + 1))      # .format为输出格式,formet括号里的即为左边花括号的输出
    print('*' * 10)
    running_loss = 0.0
    running_acc = 0.0

    # 遍历整个数据集
    for i, data in enumerate(train_loader, 1):
        img, label = data
        img = Variable(img)
        label = Variable(label)
        # print(img.data)
        # 向前传播
        out = model(img)
        # print(out.data.shape, img.shape, label.shape)
        # 计算loss
        loss = criterion(out, label)
        # 计算总的loss
        running_loss += loss.item() * label.size(0)
        _, pred = torch.max(out, 1)
        num_correct = (pred == label).sum()
        # 准确度
        accuracy = (pred == label).float().mean()
        running_acc += num_correct.item()
        # 向后传播
        optimizer.zero_grad()
        loss.backward()
        # 优化器执行
        optimizer.step()
    # 输出训练接的准确率和误差
    print('Finish {} epoch, Loss: {:.6f}, Acc: {:.6f}'.format(
        epoch + 1, running_loss / (len(train_dataset)), running_acc / (len(train_dataset))))
    # 以下未测试集
    # 模型复原
    model.eval()
    eval_loss = 0
    eval_acc = 0
    for data in test_loader:
        img, label = data
        # 测试集计算不再计算梯度
        with torch.no_grad():
            img = Variable(img)
            label = Variable(label)
        out = model(img)
        # 计算loss
        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))))
    print()
    # loss小于特定值则退出训练
    if running_loss / (len(train_dataset)) <= 0.005:
        break
# 保存模型
# torch.save(model.state_dict(), './cnn.pth')
# torch.save(model, "cnn1.pkl")
# model = torch.load("cnn1.pkl")

# 测试保存的模型
criterion = nn.CrossEntropyLoss()
eval_loss = 0
eval_acc = 0
count = 0
for data in test_loader:
    img, label = data
    with torch.no_grad():
        img = Variable(img)
        label = Variable(label)
    out = model(img)

    count += 1
    # print(out.shape, count)
    loss = criterion(out, label)
    # print(loss)
    #print(label.size(0))
    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))))
print()

代码比较乱,可能看明白需要一点时间。基本注释已经写明,不清楚请在下方留言。

完整源代码: https://github.com/mengxiangke/Lenet5

六、结果图

对于手写数字识别,效果还是蛮好的。

代码可能需要好好看一会才能看懂,若是不明白请在下方留言。

标签: CNN Lenet5 Pytorch 人工智能 深度学习
最后更新:2020年2月19日

小菜菜

菜鸟

打赏 点赞
< 上一篇
下一篇 >

文章评论

  • 要

    好

    2020年4月17日
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复

    此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据。

    联系方式

    QQ群 | TG群 | 邮箱

    最新 热点 随机
    最新 热点 随机
    Azure Student 微软云 学生订阅 免费12个月用量避坑注意点集合 MP3音频文件格式详细解析 python按固定采样点个数分割wav格式音频 愉快使用谷歌免费人工智能平台colab,训练你的神经网络模型,为你的学术生活添砖加瓦 华为云版轻量应用服务器-云耀云服务器简单体验评测 Cloudflare 免费CDN自定义节点ip之自选cloudflare 高速节点ip工具分享
    Cloudflare 免费CDN自定义节点ip之自选cloudflare 高速节点ip工具分享 吐槽电信校园宽带的坑 微软新谷歌chromium内核Edge浏览器下载与简单使用体验 C语言fwrite函数 提供一个科学上网工具 woedpress纯代码实现自动翻译成英文文章别名
    标签聚合
    ppt c语言 onedrive 地震学程序 宝塔面板 虚拟机 wordpress 模板
    最近评论
    小菜菜 发布于 6 个月前(11月24日) 这玩意已经废了,成收割工具了,不能再用了。
    eamon 发布于 7 个月前(11月07日) 我一年不用了才发现这个休眠管理费每月15,一共扣了我135元,然后我消费还消费不了,我宁愿消费掉也不...
    magic 发布于 11 个月前(07月03日) 请问账号不注销会有什么影响吗?
    magic 发布于 11 个月前(07月01日) 我想问一下 如果不注销账号就留着会怎么样
    qwp6601 发布于 12 个月前(06月04日) 有没有方法改为bing

    COPYRIGHT © 2021 shanyemangfu.com. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    蜀ICP备15031791号-2