一、基本概念
(一)框架
框架:Pytorch
入门Pytorch框架参考:
http://t.csdnimg.cn/IJvsYhttp://t.csdnimg.cn/IJvsY
(二)数据集
数据集:MNIST
1.手写数字图片7万张(其中,训练集6万张,测试集1万张)
2.每张图片是28*28像素,灰度值为0-255
(三)神经网络原理
什么是神经网络?它是如何识别图片的?
1.假设有5*5的矩阵,共25个节点,每个节点的值为0或1,把这25个节点排成1列
2.构造神经网络的第一层节点,这层节点的值是由前一层节点计算得到的
如何计算?
假设第0层节点上的数值为X0_0,X0_1,X0_2...,X0_24,
那么第1层节点上的X1_0是这样计算的:
同理,可以计算第1层神经网络下,其他节点的数值:
这里的i表示前一层节点的数值,j表示这一层节点的序号
如果要构建多层神经网络,那么公式还可以扩展成:
其中,字母含义:
i:前一层节点的数值
j:这一层节点的序号
k:网络层数
如图所示:
最后一层页脚输出层,一共有10个,因为识别的是数字0-9,共有10种结果
(四)归一化
softmax归一化步骤:
1.用自然常数e对输出节点的每一个数值做指数运算,这样结果就都为正数了;
2.再求和,用求和的值当分母,这样就得到了一组大于0,小于1,且总和为1的数组
训练的原理:
神经网络的本质:
数学函数
训练的本质:
调整参数
(五)激活函数
上面的是线性问题,但很多时候需要解决非线性问题,这个时候就需要套上一层非线性函数,也称激活函数:
常见的激活函数有很多,只要非线性即可:
二、代码
1.安装插件
pip install numpy torch torchvision matplotlib
2.定义一个Net类
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
#下面是四个全链接层
self.fc1 = torch.nn.Linear(28*28,64) #输入是28*28像素尺寸的图像
self.fc2 = torch.nn.Linear(64,64) #中间第一层:64个节点
self.fc3 = torch.nn.Linear(64,64) #中间第二层:64个节点
self.fc4 = torch.nn.Linear(64,10) #中间第三层:64个节点,输出为10个数字类别
#定义了前向传播过程(参数x:图像输入)
def forword(self,x):
# 每层传播中,先执行self.fc(x),做全链接线性计算
# torch.nn.functional.relu(),这是激活函数
x = torch.nn.functional.relu(self.fc1(x))
x = torch.nn.functional.relu(self.fc2(x))
x = torch.nn.functional.relu(self.fc3(x))
#输出层通过softmax做归一化,其中,log_softmax是为了提高计算的稳定性,因此在softmax之外又套上了一层对数运算
x = torch.nn.functional.log_softmax(self.fc4(x),dim=1)
return x
3.下载MINIST数据集
def get_data_loader(is_train):
#tensor是一个多维数组,也叫张量
to_tensor = transforms.Compose([transforms.ToTensor()])
#下载MNIST数据集,MNIST(参数1:导入的目录,参数2:导入训练集还是测试集,)
data_set = MNIST("", is_train, transform=to_tensor, download=True)
#batch_size=15表示一个批次包含15张照片;shuffle=True表示数据是随机打乱的
#函数的最后返回DataLoader数据加载器
return DataLoader(data_set, batch_size=15, shuffle=True)
4.评估神经网络的识别正确率
def evaluate(test_data, net):
n_correct = 0 #正确预测的数量
n_total = 0 #预测的总数量
with torch.no_grad():
for (x, y) in test_data: #从测试集test_data中按批次取出数据
#计算神经网络的预测值
outputs = net.forword(x.view(-1, 28*28))
#对批次中的每个结果进行比较
for i, output in enumerate(outputs):
if torch.argmax(output) == y[i]: #argmax():计算一个数列中最大值的序号(也就是预测手写数字的结果)
n_correct +=1
n_total+=1
#返回正确率
return n_correct / n_total
5.主函数
def main():
#1--导入训练集和测试集
train_data = get_data_loader(is_train=True)
test_data = get_data_loader(is_train=False)
#2--初始化神经网络
net = Net()
#3--打印初始网络的正确率(接近0.1)
print("initial accuracy:", evaluate(test_data, net))
#4--训练神经网络
optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
#epoch:有时候需要在一个神经网络上反复训练数据集,这样可以提高数据集的利用率,每一轮就是一个epoch
for epoch in range(2):
for(x,y) in train_data:
# 初始化
net.zero_grad()
# 正向传播
output = net.forword(x.view(-1,28*28))
#计算差值
loss = torch.nn.functional.nll_loss(output,y) #nll_loss:对数损失函数,为了匹配前面log_softmax的运算
#反向误差传播
loss.backward()
#优化网络参数
optimizer.step()
#打印当前网络的正确率
print("epoch",epoch,"accuracy:",evaluate(test_data,net))
#训练结束后,随机抽取三张图像,显示网络预测的结果
for(n, (x, _)) in enumerate(test_data):
if n>3:
break
predict = torch.argmax(net.forword(x[0].view(-1,28*28)))
plt.figure(n)
plt.imshow(x[0].view(28,28))
plt.title("prediction: " + str(int(predict)))
plt.show()
6.启动主函数
if __name__ == '__main__':
main()
7.完整代码
import torch
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST
import matplotlib.pyplot as plt
# 定义一个Net类
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
#下面是四个全链接层
self.fc1 = torch.nn.Linear(28*28,64) #输入是28*28像素尺寸的图像
self.fc2 = torch.nn.Linear(64,64) #中间第一层:64个节点
self.fc3 = torch.nn.Linear(64,64) #中间第二层:64个节点
self.fc4 = torch.nn.Linear(64,10) #中间第三层:64个节点,输出为10个数字类别
#定义了前向传播过程(参数x:图像输入)
def forword(self,x):
# 每层传播中,先执行self.fc(x),做全链接线性计算
# torch.nn.functional.relu(),这是激活函数
x = torch.nn.functional.relu(self.fc1(x))
x = torch.nn.functional.relu(self.fc2(x))
x = torch.nn.functional.relu(self.fc3(x))
#输出层通过softmax做归一化,其中,log_softmax是为了提高计算的稳定性,因此在softmax之外又套上了一层对数运算
x = torch.nn.functional.log_softmax(self.fc4(x),dim=1)
return x
def get_data_loader(is_train):
#tensor是一个多维数组,也叫张量
to_tensor = transforms.Compose([transforms.ToTensor()])
#下载MNIST数据集,MNIST(参数1:导入的目录,参数2:导入训练集还是测试集,)
data_set = MNIST("", is_train, transform=to_tensor, download=True)
#batch_size=15表示一个批次包含15张照片;shuffle=True表示数据是随机打乱的
#函数的最后返回DataLoader数据加载器
return DataLoader(data_set, batch_size=15, shuffle=True)
#evaluate用于评估神经网络的识别正确率
def evaluate(test_data, net):
n_correct = 0 #正确预测的数量
n_total = 0 #预测的总数量
with torch.no_grad():
for (x, y) in test_data: #从测试集test_data中按批次取出数据
#计算神经网络的预测值
outputs = net.forword(x.view(-1, 28*28))
#对批次中的每个结果进行比较
for i, output in enumerate(outputs):
if torch.argmax(output) == y[i]: #argmax():计算一个数列中最大值的序号(也就是预测手写数字的结果)
n_correct +=1
n_total+=1
#返回正确率
return n_correct / n_total
def main():
#1--导入训练集和测试集
train_data = get_data_loader(is_train=True)
test_data = get_data_loader(is_train=False)
#2--初始化神经网络
net = Net()
#3--打印初始网络的正确率(接近0.1)
print("initial accuracy:", evaluate(test_data, net))
#4--训练神经网络
optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
#epoch:有时候需要在一个神经网络上反复训练数据集,这样可以提高数据集的利用率,每一轮就是一个epoch
for epoch in range(2):
for(x,y) in train_data:
# 初始化
net.zero_grad()
# 正向传播
output = net.forword(x.view(-1,28*28))
#计算差值
loss = torch.nn.functional.nll_loss(output,y) #nll_loss:对数损失函数,为了匹配前面log_softmax的运算
#反向误差传播
loss.backward()
#优化网络参数
optimizer.step()
#打印当前网络的正确率
print("epoch",epoch,"accuracy:",evaluate(test_data,net))
#训练结束后,随机抽取三张图像,显示网络预测的结果
for(n, (x, _)) in enumerate(test_data):
if n>3:
break
predict = torch.argmax(net.forword(x[0].view(-1,28*28)))
plt.figure(n)
plt.imshow(x[0].view(28,28))
plt.title("prediction: " + str(int(predict)))
plt.show()
if __name__ == '__main__':
main()
三、运行结果
可以看出,初始预测的准确率为0.0958,第一个epoch后,准确率达到了0.0562,第二个epoch下准确率达到了0.9665,故实验完毕。
四、本文参考来源
【10分钟入门神经网络 PyTorch 手写数字识别】https://www.bilibili.com/video/BV1GC4y15736?vd_source=7e977d0187273d77005659cdd86927dfhttp://【10分钟入门神经网络 PyTorch 手写数字识别】https://www.bilibili.com/video/BV1GC4y15736?vd_source=7e977d0187273d77005659cdd86927df