山野莽夫

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

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

2020年2月19日 3042点热度 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来减少垃圾评论。了解我们如何处理您的评论数据。

    标签聚合
    wordpress 宝塔面板 onedrive 模板 虚拟机 c语言 ppt 地震学程序
    最新 热点 随机
    最新 热点 随机
    Azure Student 微软云 学生订阅 免费12个月用量避坑注意点集合 MP3音频文件格式详细解析 python按固定采样点个数分割wav格式音频 愉快使用谷歌免费人工智能平台colab,训练你的神经网络模型,为你的学术生活添砖加瓦 华为云版轻量应用服务器-云耀云服务器简单体验评测 Cloudflare 免费CDN自定义节点ip之自选cloudflare 高速节点ip工具分享
    C语言中n层循环嵌套实现 使用CloudFlare Workers 零成本部署 OneDrive 文件列表程序FODI(Fast OneDrive Index) 二层电测深电阻率正演模拟 wp备份插件wp-clone(可以用来完美搬家) 四川电信校园宽带拨号问题 字符串穷举C语言算法域名查询

    COPYRIGHT © 2021 shanyemangfu.com. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    蜀ICP备15031791号-2