基于Pytorch框架的Mnist网络实现和详解
文章首先感谢莫凡大神的pytorch教学视频,附链接:https://morvanzhou.github.io/tutorials/machine-learning/torch/
对深度学习感兴趣的小伙伴可以去看一下!
神经网络简化示意图:
1. 什么是卷积神经网络(CNN):
卷积神经网络(CNN——Convolutional Neural Network)是一种前馈神经网络。人工神经元可以响应周围单元。卷积神经网络包括卷积层和池化层。
2. 卷积神经网络的结构:
最左边的Image是输入层(Input Layer),首先,我们要有一个概念,对于我们人来说输入的是一张图片,但是对于电脑来说输入的是一个矩阵类型的数据,这些数据代表着这张图片的像素值。接着是卷积层(Convolution Layer),这一层的功能可以理解为:对输入的数据进行特征提取,每个卷积核每次从一个小区域提取到一个特征值,所有的特征值组合起来就得到了一个特征图,当用多个卷积核对输入数据进行特征提取时,就得到了多个特征图。这个卷积核我们称为(kernel)。再接着是池化层(Pooling Layer),所谓池化就是在不影响特征质量的情况下对图片进行压缩,以减少参数,池化主要有两种,一种是MaxPooling,一种是AvePooling。假设池化的内核是一个2*2的矩阵,采用MaxPooling则是输出其中的最大值,采用AvePooling则输出所有数据的平均值。
卷积+池化的组合可以在隐藏层中出现多次,上图中出现2次,而实际上则需要根据实际需求而来。在经过多次的卷积+池化之后是全连接层(Fully Connected Layer,简称FC),最后是输出层(Output Layer)。
3. Pytorch介绍:
Pytorch是Torch7团队开发的,与Torch的不同之处在于Pytorch使用了Python作为开发语言,同样说明它是一个以Python优先的深度学习框架,它不仅能够实现强大的GPU加速,同时还支持动态神经网络,这是TensorFlow等很多主流框架不支持的。而且Pytorch可以轻松扩展。
Pytorch中有两种变量类型,一种是Tensor,一种是Variable。并且Tensor和Numpy之间可以自由转换。
有了这些基础概念,我们可以接下来手动写一个典型的CNN网络——Mnist网络:
要实现这个网络可以分为以下几个步骤:
1. 数据下载和预处理
2. 定义网络模型,即Mnist网络
3. 训练网络
4. 测试网络
代码实现:
#1.数据预处理
data_tf = torchvision.transforms.Compose(
[torchvision.transforms.ToTensor(),#将输入转换为Tensor的格式
torchvision.transforms.Normalize([0.5],[0.5])] #归一化处理[-1,1],因为黑白图片的depth是1,如果是彩色图片,输入depth,则torchvision.transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])
)
# 2.下载(读取)数据
train_data = torchvision.datasets.MNIST(
root = 'W:/pic_data',#下载的图片存放的路径
train = True,
transform = data_tf,
download = True #True代表下载,如果已经下载完成可以设置为False
)
train_dataloader = DataLoader(train_data,batch_size = Batch_size,shuffle = True)
test_data = torchvision.datasets.MNIST(
root = 'W:/pic_data',
train = False,
transform = data_tf
)
test_dataloader = DataLoader(test_data,batch_size = Batch_size,shuffle =False)
2. 定义网络模型:
class my_mnist(nn.Module):
def __init__(self):
super(my_mnist,self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1,16,5,1,2),#输入是1,输出是16,卷积核是5*5,每次移动1步,每一条边补充2行/列0,经过这一步之后,数据由1*28*28,变成了16*28*28
nn.ReLU(),#激活函数
nn.MaxPool2d(2)#卷积核是2*2,即每2*2的矩阵中的4个数据选取一个最大值,这样就由16*28*28,变成了16*14*14
)
self.layer2 = nn.Sequential(
nn.Conv2d(16,32,5,1,2),#16*14*14 --> 32*14*14
nn.ReLU(),
nn.MaxPool2d(2)#32*14*14 -->32*7*7
)
self.layer3 = nn.Linear(32*7*7,10)#output = 10,是因为0-9有10个数,代表输出有10种可能。
def forward(self,x):
x = self.layer1(x)
x = self.layer2(x)
x = x.view(x.size(0),-1)#经过layer2之后x的size是(n,c,h,w),这一步的作用可以理解为将图片碾压成平面,即(1,32,7,7)-->(1,32*7*7)
out = self.layer3(x)
return out
#注意:模型的建立是在forward()中实现的,之前只是在堆建框架及设置参数。
Parameters:
· in_channels(int) – 输入信号的通道
· out_channels(int) – 卷积产生的通道,可以理解为有多少个采集器
· kerner_size(int or tuple) - 卷积核的尺寸
· stride(int or tuple, optional) - 卷积步长,卷积每次移动的距离
· padding(int or tuple, optional) - 输入的每一条边补充0的层数
· dilation(int or tuple, optional) – 卷积核元素之间的间距
· groups(int, optional) – 从输入通道到输出通道的阻塞连接数
· bias(bool, optional) - 如果bias=True,添加偏置
参数:
· kernel_size(int or tuple) - max pooling的窗口大小
· stride(int or tuple, optional) - max pooling的窗口移动的步长。默认值是kernel_size
· padding(int or tuple, optional) - 输入的每一条边补充0的层数
· dilation(int or tuple, optional) – 一个控制窗口中元素步幅的参数
· return_indices - 如果等于True,会返回输出最大值的序号,对于上采样操作会有帮助
· ceil_mode - 如果等于True,计算输出信号大小的时候,会使用向上取整,代替默认的向下取整的操作
‘’’
#接着导入网络,定义损失函数和优化方法:
net = my_mnist()
#print(net)
loss_func = nn.CrossEntropyLoss()#定义损失函数
optimizer = torch.optim.Adam(net.parameters(),lr = lean_rate)#定义优化器
3. 训练网络:
for epoch in range(500):
running_loss = 0
running_acc = 0
for (x,y) in train_dataloader:
x_input = Variable(x)
y_target = Variable(y)
output = net(x_input)
loss = loss_func(output,y_target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
running_loss += loss.data[0]
_, predict = torch.max(output, 1)#1代表在行这个维度,最大的数
correct_num = (predict == y_target).sum()
running_acc += correct_num.data[0]
running_loss /= len(train_data)
running_acc /= len(train_data)
print("[%d] Loss: %.5f, Acc: %.2f" %(epoch, running_loss, 100*running_acc))
if running_loss <0.002:
Break
4. 测试网络:
net.eval()#将网络改成测试模式
for (img,label) in test_dataloader:
test_img = Variable(img)
label = Variable(label)
test_out = net(test_img)
_, predict = torch.max(test_out, 1)
print('test_out:',predict,
'label:',label)
总结代码如下:
import torch
from torch.autograd import Variable
import torch.nn as nn
import torchvision
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader
Epoch = 1
Batch_size = 32
lean_rate = 0.001
Download_Minist = False
#1.数据预处理
data_tf = torchvision.transforms.Compose(
[torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize([0.5],[0.5])] #归一化处理[-1,1]
)
# 2.下载(读取)数据
train_data = torchvision.datasets.MNIST(
root = 'W:/pic_data',
train = True,
transform = data_tf,
download = Download_Minist
)
train_dataloader = DataLoader(train_data,batch_size = Batch_size,shuffle = True)
test_data = torchvision.datasets.MNIST(
root = 'W:/pic_data',
train = False,
transform = data_tf
)
test_dataloader = DataLoader(test_data,batch_size = Batch_size,shuffle =False)
'''
#打印第一张图片
print(train_data.train_data.size())
print(train_data.train_labels.size())
plt.imshow(train_data.train_data[0].numpy(),cmap = 'gray')
plt.title('%i'%(train_data.train_labels[0]))
plt.show()
'''
#3.自定义训练网络模型
class my_mnist(nn.Module):
def __init__(self):
super(my_mnist,self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1,16,5,1,2),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.layer2 = nn.Sequential(
nn.Conv2d(16,32,5,1,2),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.layer3 = nn.Linear(32*7*7,10)
def forward(self,x):
x = self.layer1(x)
x = self.layer2(x)
x = x.view(x.size(0),-1)
out = self.layer3(x)
return out
net = my_mnist()
#print(net)
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(),lr = lean_rate)
#5.训练网络
for epoch in range(500):
running_loss = 0
running_acc = 0
for (x,y) in train_dataloader:
x_input = Variable(x)
y_target = Variable(y)
output = net(x_input)
loss = loss_func(output,y_target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
running_loss += loss.data[0]
_, predict = torch.max(output, 1)#1代表在行这个维度,最大的数
correct_num = (predict == y_target).sum()
running_acc += correct_num.data[0]
running_loss /= len(train_data)
running_acc /= len(train_data)
print("[%d] Loss: %.5f, Acc: %.2f" %(epoch, running_loss, 100*running_acc))
if running_loss <0.002:
break
#测试网络
net.eval()
for (img,label) in test_dataloader:
test_img = Variable(img)
label = Variable(label)
test_out = net(test_img)
_, predict = torch.max(test_out, 1)
print('test_out:',predict,
'label:',label)
PS:第一次写博客,欢迎大神指教。允许转载,请注明作者和出处。