cnn官网

更新时间:2022-12-27 20:44:42 阅读: 评论:0


2022年12月27日发(作者:四六级官网报名网站)

pytorch实战动⼿设计CNN+MNIST⼿写体数字识别

⽂章⽬录

前⾔

相信对于每⼀个刚刚上⼿深度学习的孩⼦来说,利⽤mnist数据集来训练⼀个CNN是再好不过的学习demo了。

本⽂使⽤pytorch来动⼿搭建⼀个卷积神经⽹络来训练和预测⼿写数字。通过本⽂,你将了解到pytorch的⼀些功能:

1.⾼效加载数据集;

2.简单灵活地设计神经⽹络;

3.了解对训练和泛化有帮助的⽹络结构tricks(如batchnorm,dropout)

4.学习优化器(⼀般⽤adam);

5.神经⽹络的损失函数(⼀般⽤交叉熵);

6.学习率的动态调节(学习率的动态变化);

h训练过程(尤其是批量进⾏的训练⽅式mini-batch)

h预测的过程

接下来就开始啦,每⼀部分的代码我尽量搭配详细的注释,让你快速理解,轻松上⼿pytorch!

引⼊库函数

importtorch#pytorch最基本模块

#pytorch中最重要的模块,封装了神经⽹络相关的函数

onalasF#提供了⼀些常⽤的函数,如softmax

soptim#优化模块,封装了求解模型的⼀些优化器,如AdamSGD

mportlr_scheduler#学习率调整器,在训练过程中合理变动学习率

fromtorchvisionimporttransforms#pytorch视觉库中提供了⼀些数据变换的接⼝

fromtorchvisionimportdatats#pytorch视觉库提供了加载数据集的接⼝

预设超参数

#预设⽹络超参数(所谓超参数就是可以⼈为设定的参数

BATCH_SIZE=64#由于使⽤批量训练的⽅法,需要定义每批的训练的样本数⽬

EPOCHS=2#总共训练迭代的次数

#让torch判断是否使⽤GPU,建议使⽤GPU环境,因为会快很多

DEVICE=("cuda"_available()el"cpu")

learning_rate=0.1#设定初始的学习率

加载数据集

像MNIST这么知名的数据集,pytorch居然内置了对应的加载接⼝,真的优秀!不过第⼀次使⽤我们会下载数据集到⼀个⽂件夹中,以后就

可以直接读取该⽂件夹内部的数据了。这⾥我们使⽤dataloader迭代器来加载数据集,题外话:迭代器的作⽤可以减少内存的占⽤。

#加载训练集

train_loader=ader(

('data',train=True,download=True,

transform=e([

or(),

ize(mean=(0.5,),std=(0.5,))#数据规范化到正态分布

])),

batch_size=BATCH_SIZE,shuffle=True)#指明批量⼤⼩,打乱,这是处于后续训练的需要。

test_loader=ader(

('data',train=Fal,transform=e([

or(),

ize((0.5,),(0.5,))

])),

batch_size=BATCH_SIZE,shuffle=True)

上述代码的作⽤是:

1.将mnist训练集和测试集下载到⽂件夹data中

2.对数据进⾏变化,包括转为tensor数据类型,以及为了保证训练集测试集的独⽴同分布,数据规范化到正态分布

3.数据分批量存储,顺序打乱,⽅便后续训练。

设计CNN

⼀个简单的卷积神经⽹络的结构,⼀般包括:

卷积层Conv:通过卷积核提取图像特征,得到featuremap

池化层Pool:利⽤卷积核对featuremap降采样,减少尺⼨。最⼤池化层就是取滑动窗⼝内最⼤的像素,⽽平均池化层就是取滑动窗

⼝内平均像素结果。

全连接层:多个linearmodel+激活函数eg:ReLU。

这样就构成了⼀个基本的CNN了,但是我们出于爱学习的⼼态呢,我们最好还要了解⼀些深度学习训练过程中的⼀些tricks,以提⾼模型的

泛化能⼒。如:

batchnormalization:简单来说就是将上⼀层的加权求和的所有输出结果再批量归⼀化(标准正态分布),然后输⼊⼀个线性模型,

然后再连接到激活函数。

DropOut:在全连接层中,我们通过设定概率随机的让这⼀层的某些权重为0,相当于神经元⽆效。

emmmm,经过⼤量时间,这两个tricks表现挺好,不知如何解释。

且看代码吧,我给每⼀个接⼝的参数进⾏了详细的解释。

#设计模型

classConvNet():

def__init__(lf):

super(ConvNet,lf).__init__()

#提取特征层

es=tial(

#卷积层

#输⼊图像通道为1,因为我们使⽤的是⿊⽩图,单通道的

#输出通道为32(代表使⽤32个卷积核),⼀个卷积核产⽣⼀个单通道的特征图

#卷积核kernel_size的尺⼨为3*3,stride代表每次卷积核的移动像素个数为1

#padding填充,为1代表在图像长宽都多了两个像素

2d(in_channels=1,out_channels=32,kernel_size=3,stride=1,padding=1),

#批量归⼀化,跟上⼀层的out_channels⼤⼩相等,以下的通道规律也是必须要对应好的

orm2d(num_features=32),

#激活函数,inplace=true代表直接进⾏运算

(inplace=True),

2d(32,32,kernel_size=3,stride=1,padding=1),

orm2d(32),

(inplace=True),

#最⼤池化层

#kernel_size为2*2的滑动窗⼝

#stride为2,表⽰每次滑动距离为2个像素

#经过这⼀步,图像的⼤⼩变为1/4,即28*28-》14*14

l2d(kernel_size=2,stride=2),

2d(32,64,kernel_size=3,padding=1),

orm2d(64),

(inplace=True),

2d(64,64,kernel_size=3,padding=1),

orm2d(64),

(inplace=True),

l2d(kernel_size=2,stride=2)#14*14-》7*7

)

#分类全连接层

fier=tial(

#Dropout层

#p=0.5代表该层的每个权重有0.5的可能性为0

t(p=0.5),

#这⾥是通道数64*图像⼤⼩7*7,然后输⼊到512个神经元中

(64*7*7,512),

orm1d(512),

(inplace=True),

t(p=0.5),

(512,512),

orm1d(512),

(inplace=True),

t(p=0.5),

(512,10),

)

defforward(lf,x):

#经过特征提取层

x=es(x)

#输出结果必须展平成⼀维向量,然后连接到全连接层

x=((0),-1)

x=fier(x)

x=_softmax(out,dim=1)#经过softmax输出,可以交叉熵损失函数搭配使⽤,便于计算

returnx

⽹络结构的设计都是⾃定义的哦!你可以有⾃⼰更奇特的想法,或者复现知名⽹络结构如LeNet等等。

训练前准备

#初始化模型,将⽹络操作移动到GPU或者CPU

ConvModel=ConvNet().to(DEVICE)

#定义交叉熵损失函数

criterion=ntropyLoss().to(DEVICE)

#定义模型优化器:输⼊模型参数,定义初始学习率

optimizer=(ters(),lr=learning_rate)

#定义学习率调度器,输⼊包装的模型,定义学习率衰减周期step_size,gamma为衰减的乘法因⼦

exp_lr_scheduler=lr_(optimizer,step_size=3,gamma=0.1)

#在官⽹上的解释。如果初始学习率lr=0.05,衰减周期step_size为30,衰减乘法因⼦gamma=0.01

#Assumingoptimizeruslr=0.05forallgroups

#>>>#lr=0.05ifepoch<30

#>>>#lr=0.005if30<=epoch<60

#>>>#lr=0.0005if60<=epoch<90

训练模块

我们把训练模块封装起来,可以保证多次调⽤。

deftrain(num_epochs,_model,_device,_train_loader,_optimizer,_lr_scheduler):

_()#设置模型为训练模式

_lr_()#设置学习率调度器开始准备更新

forepochinrange(num_epochs):

#从迭代器抽取图⽚和标签

fori,(images,labels)inenumerate(_train_loader):

samples=(_device)

labels=(_device)

#此时样本是⼀批图⽚,在CNN的输⼊中,我们需要将其变为四维,

#reshape第⼀个-1代表⾃动计算批量图⽚的数⽬n

#最后reshape得到的结果就是n张图⽚,每⼀张图⽚都是单通道的28*28,得到四维张量

output=_model(e(-1,1,28,28))

#计算损失函数值

loss=criterion(output,labels)

#优化器内部参数梯度必须变为0

_grad()

#损失值后向传播

rd()

#更新模型参数

()

if(i+1)%100==0:

print("Epoch:{}/{},step:{},loss:{:.4f}".format(epoch+1,num_epochs,i+1,()))

预测模块

deftest(_test_loader,_model,_device):

_()#设置模型进⼊预测模式evaluation

loss=0

correct=0

_grad():#如果不需要backward更新梯度,那么就要禁⽤梯度计算,减少内存和计算资源浪费。

fordata,targetin_test_loader:

data,target=(_device),(_device)

output=ConvModel(e(-1,1,28,28))

loss+=criterion(output,target).item()#添加损失值

pred=(1,keepdim=True)[1]#找到概率最⼤的下标,为输出值

correct+=(_as(pred)).cpu().sum()#.cpu()是将参数迁移到cpu上来。

loss/=len(_test_t)

print('nAverageloss:{:.4f},Accuracy:{}/{}({:.3f}%)n'.format(

loss,correct,len(_test_t),

100.*correct/len(_test_t)))

运⾏

这时封装的好处就显⽽易见啦。

forepochinrange(1,EPOCHS+1):

train(epoch,ConvModel,DEVICE,train_loader,optimizer,exp_lr_scheduler)

test(test_loader,ConvModel,DEVICE)

test(train_loader,ConvModel,DEVICE)

结果

由于训练时间有点长(我没有N卡,只能⽤CPU。。),我只训练了两个epoch,训练达到⼀定的次数,泛化能⼒会增强,但是训练过度之

后,泛化能⼒会显著下降(过拟合),合理的制定epoch,利⽤测试集(验证集)来测试最佳的epoch。

准确度还是可以的,多训练⼏次,准确度就会提升滴,加油!

总结

本⽂还是有许多可扩展的地⽅,如要提⾼准确度,可以引⼊数据增⼴的⽅法,对原始图像进⾏⼀定程度的旋转,漂移,处理后的数据来训

练,可提⾼泛化能⼒。

个⼈觉得pytorch的学习并不复杂,多接触项⽬,遇到不懂的,及时查官⽅⽂档,看接⼝,还得多⽤,⽤着⽤着就熟悉掌握啦。

更⾼阶的就是去接触⼀些前沿的论⽂,看它们开源的代码,会有更深的体会。

所以下⼀步,我的计划就是研读论⽂代码并理解,多跑跑⼀些经典模型,如ResNet;

再下⼀步⾃⼰⼿动复现代码!

届时我会把我的感想和收获分享出来!如果觉得本⽂对你有所帮助,请为我点个赞好么^^

完整代码

见我的github:。

本文发布于:2022-12-27 20:44:42,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/90/42537.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:cnn官网
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图