特点:
- 实现模型保存与加载,训练结果不丢失
- 实现数据可视化
- 测试过程可交互,可以选择测试哪一条数据
Step1:准备数据。
(1)数据集介绍
MNIST数据集包含60000个训练集和10000测试数据集。分为图片和标签,图片是28*28的像素矩阵,标签为0~9共10个数字。
# 导包 与参数保存路径设置
import paddle
from paddle.vision.transforms import ToTensor
import os
import paddle.nn as nn
import paddle.nn.functional as F
import matplotlib.pyplot as plt
modelpath,optpath="linear_net.pdparams","adam.pdopt"
# # 加载数据函数
def getdata():
print("data loading",end="\r")
# 加载数据集
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=ToTensor())
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=ToTensor())
# 用 DataLoader 实现数据加载
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
# 加载测试数据集
test_loader = paddle.io.DataLoader(test_dataset, batch_size=64, drop_last=True)
print("data loaded ")
return train_loader, test_loader
# train_loader, test_loader=getdata()
# 加载数据集
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=ToTensor())
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=ToTensor())
#让我们一起看看数据集中的图片是什么样子的
train_data0, train_label_0 = test_dataset[5][0],test_dataset[5][1]
train_data0 = train_data0.reshape([28,28])
plt.figure(figsize=(2,2))
print(plt.imshow(train_data0, cmap=plt.cm.binary))
print('train_data0 的标签为: ' + str(train_label_0))
AxesImage(25,22;155x154) train_data0 的标签为: [1]
#让我们再来看看数据样子是什么样的吧
print(train_data0)
Tensor(shape=[28, 28], dtype=float32, place=CUDAPlace(0), stop_gradient=True, [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.30196080, 0.99607849, 0.41960788, 0.01176471, 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.07450981, 0.89019614, 0.99607849, 0.99607849, 0.03529412, 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.31764707, 0.99607849, 0.99607849, 0.64705884, 0.00392157, 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.02745098, 0.79607850, 0.99607849, 0.99607849, 0.28627452, 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.20784315, 0.99607849, 0.99607849, 0.98039222, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.52549022, 0.99607849, 0.99607849, 0.70588237, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.76862752, 0.99607849, 0.97254908, 0.18823531, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.22745100, 0.99607849, 0.99607849, 0.92941183, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.43529415, 0.99607849, 0.99607849, 0.51764709, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.63921571, 0.99607849, 0.93333340, 0.10980393, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.23529413, 0.98823535, 0.99607849, 0.87450987, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.30980393, 0.99607849, 0.99607849, 0.60392159, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.63921571, 0.99607849, 0.93333340, 0.20784315, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.10980393, 0.98823535, 0.99607849, 0.82352948, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.33725491, 0.99607849, 0.99607849, 0.51372552, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.41176474, 0.99607849, 0.91764712, 0.07843138, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.68627453, 0.99607849, 0.80000007, 0.01960784, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.01960784, 0.82745105, 0.99607849, 0.76862752, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.01176471, 0.61960787, 0.99607849, 0.62745100, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.10196079, 0.61568630, 0.41960788, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
# 用 DataLoader 实现数据加载
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
# 加载测试数据集
test_loader = paddle.io.DataLoader(test_dataset, batch_size=64, drop_last=True)
print("data loaded ")
data loaded
# 显示图像函数
def showimg(img):
plt.figure("Image") # 图像窗口名称
plt.imshow(img, cmap=plt.cm.binary)
plt.axis('on') # 关掉坐标轴为 off
plt.title('image') # 图像题目
plt.show()
# # 保存和加载参数函数
# def savemodel(layer,adam):
# # save
# print("saving model",end="\r")
# paddle.save(layer.state_dict(),modelpath )
# paddle.save(adam.state_dict(),optpath )
# print("saved model ")
# def loadmodel(layer,adam):
# # load
# if os.path.isfile(modelpath) and os.path.isfile(optpath):
# print("not first train,loading para",end="\r")
# layer_state_dict = paddle.load(modelpath)
# layer.set_state_dict(layer_state_dict)
# opt_state_dict = paddle.load(optpath)
# adam.set_state_dict(opt_state_dict)
# print("not first train,loaded para ")
# else:
# print("first train!")
# 保存和加载参数函数
def savemodel(layer):
# save
print("saving model",end="\r")
paddle.save(layer.state_dict(),modelpath )
# paddle.save(adam.state_dict(),optpath )
print("saved model ")
def loadmodel(layer):
# load
if os.path.isfile(modelpath):
print("not first train,loading para",end="\r")
layer_state_dict = paddle.load(modelpath)
layer.set_state_dict(layer_state_dict)
# opt_state_dict = paddle.load(optpath)
# adam.set_state_dict(opt_state_dict)
print("not first train,loaded para ")
else:
print("first train!")
Step2.网络配置
以下的代码判断就是定义一个简单的多层感知器,一共有三层,两个大小为100的隐层和一个大小为10的输出层,因为MNIST数据集是手写0到9的灰度图像,类别有10个,所以最后的输出大小是10。最后输出层的激活函数是Softmax,所以最后的输出层相当于一个分类器。加上一个输入层的话,多层感知器的结构是:输入层-->>隐层-->>隐层-->>输出层。
# 定义多层感知器
#动态图定义多层感知器
class DNN(paddle.nn.Layer):
def __init__(self):
super(DNN,self).__init__()
self.fc1 = paddle.nn.Linear(in_features =28*28, out_features =100)#输入层
self.fc2 = paddle.nn.Linear(in_features =100, out_features =100)#隐藏层设置100个神经元
self.fc3 = paddle.nn.Linear(in_features =100, out_features =10)#输出层 10个神经元对应10种数字
def forward(self, input_):
x = paddle.reshape(input_, [input_.shape[0], -1])
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
x = F.relu(x)
x = self.fc3(x)
y = F.softmax(x)
return y
#BP 网络结构函数
class Mnist(paddle.nn.Layer):
def __init__(self):
super(Mnist, self).__init__()
self.flatten = paddle.nn.Flatten()
self.linear_1 = paddle.nn.Linear(784, 512)#隐藏层512个神经源
self.linear_2 = paddle.nn.Linear(512, 10)
self.relu = paddle.nn.ReLU()
self.dropout = paddle.nn.Dropout(0.2)
def forward(self, inputs):
y = self.flatten(inputs)
y = self.linear_1(y)
y = self.relu(y)
y = self.dropout(y)
y = self.linear_2(y)
return y
Step3.自己搭建一个BP神经网络
参考上面两个网络的搭建方法,搭建自己的网络,将代码写到下面code框中, 并进行后续训练、评估和测试
class Mnist1(paddle.nn.Layer):
def __init__(self):
super(Mnist1, self).__init__()
self.flatten = paddle.nn.Flatten()
self.linear_1 = paddle.nn.Linear(784, 512)#隐藏层512个神经源
self.linear_2 = paddle.nn.Linear(512, 256)#隐藏层256个神经源
self.linear_3 = paddle.nn.Linear(256, 128)#隐藏层128个神经源
self.linear_4 = paddle.nn.Linear(128, 10)#分为10类
self.relu = paddle.nn.ReLU()
self.dropout = paddle.nn.Dropout(0.2)
def forward(self, inputs):
y = self.flatten(inputs)
y = self.linear_1(y)
y = self.relu(y)
y = self.dropout(y)
y = self.linear_2(y)
y = self.relu(y)
y = self.dropout(y)
y = self.linear_3(y)
y = self.relu(y)
y = self.dropout(y)
y = self.linear_4(y)
return y
Step4.训练
# 训练函数--输入 网络、训练数据、epoch、优化器、损失函数 训练
def train(mnist,train_loader,epochs,optim,loss_fn):
print("train begin")
mnist.train()
for epoch in range(epochs):
for batch_id, data in enumerate(train_loader()):
x_data = data[0] # 训练数据
y_data = data[1] # 训练数据标签
predicts = mnist(x_data) # 预测结果
# 计算损失 等价于 prepare 中loss的设置
loss = loss_fn(predicts, y_data)
# 计算准确率 等价于 prepare 中metrics的设置
acc = paddle.metric.accuracy(predicts, y_data)
# 下面的反向传播、打印训练信息、更新参数、梯度清零都被封装到 Model.fit() 中
# 反向传播
loss.backward()
if (batch_id+1) % 900 == 0:
print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id+1, loss.numpy(), acc.numpy()))
# 更新参数
optim.step()
# 梯度清零
optim.clear_grad()
if epochs>0:savemodel(mnist)
#BP
# mnist=Mnist()
#DNN
mnist = Mnist1()
optim = paddle.optimizer.Adam(parameters=mnist.parameters()) # 设置优化器
loadmodel(mnist)
loss_fn = paddle.nn.CrossEntropyLoss() # 设置损失函数
not first train,loaded para
epochs = int(input("train times:")) # 设置迭代次数
train(mnist,train_loader,epochs,optim,loss_fn)
train times: 3
train begin epoch: 0, batch_id: 900, loss is: [0.09206763], acc is: [0.984375] epoch: 1, batch_id: 900, loss is: [0.05399161], acc is: [0.984375] epoch: 2, batch_id: 900, loss is: [0.11109874], acc is: [0.984375] saved model
Step5.评估
# 评估函数
def eval(mnist,test_loader,loss_fn):
mnist.eval()
for batch_id, data in enumerate(test_loader()):
x_data = data[0] # 测试数据
y_data = data[1] # 测试数据标签
predicts = mnist(x_data) # 预测结果
# 计算损失与精度
loss = loss_fn(predicts, y_data)
acc = paddle.metric.accuracy(predicts, y_data)
# 打印信息
if (batch_id+1) % 30 == 0:
print("batch_id: {}, loss is: {}, acc is: {}".format(batch_id+1, loss.numpy(), acc.numpy()))
eval(mnist,test_loader,loss_fn)
batch_id: 30, loss is: [0.09358358], acc is: [0.984375] batch_id: 60, loss is: [0.27202883], acc is: [0.9375] batch_id: 90, loss is: [0.03672048], acc is: [0.984375] batch_id: 120, loss is: [3.5817196e-05], acc is: [1.] batch_id: 150, loss is: [0.07554816], acc is: [0.984375]
Step6.测试
# 测试函数 输入大于等于10000或小于0的数字会停止测试 退出程序
def test(mnist,test_loader):
mnist.eval()
alldata={}
allpredicts={}
alllabel={}
for batch_id, data in enumerate(test_loader()):
x_data = data[0]
y_data = data[1]
predicts = mnist(x_data)
allpredicts[batch_id]=predicts
alllabel[batch_id]=y_data
alldata[batch_id]=x_data
i=0
while i<10000 and i>=0:
batch_id=i//64
id=i%64
print("predict:",allpredicts[batch_id][id].argmax().numpy().tolist(),
"label:",alllabel[batch_id][id].numpy().tolist())
print("network output:",allpredicts[batch_id][id].numpy().tolist())
img=(alldata[batch_id][id][0]).numpy()
showimg(img)
i=int(input("predict which line:"))
print("predict finished")
test(mnist,test_loader)
predict: [7] label: [7] network output: [-9.719499588012695, -3.4801108837127686, -0.651482880115509, 0.385851114988327, -2.0601513385772705, -7.415570259094238, -16.08660888671875, 16.32851791381836, -4.776862621307373, -3.5384793281555176]
<Figure size 640x480 with 1 Axes>
predict which line: 1
predict: [2] label: [2] network output: [-6.095338821411133, 1.228253960609436, 19.041542053222656, 0.19300922751426697, -6.705218315124512, -6.877689838409424, -7.77207612991333, -2.713935613632202, 1.3736858367919922, -16.818513870239258]
<Figure size 640x480 with 1 Axes>
predict which line: 2
predict: [1] label: [1] network output: [-6.339268207550049, 17.581079483032227, -1.0753511190414429, -9.902815818786621, -4.157736301422119, -9.313263893127441, -3.4409077167510986, 2.3445217609405518, -3.7683358192443848, -10.679972648620605]
<Figure size 640x480 with 1 Axes>
predict which line: 3
predict: [0] label: [0] network output: [13.701967239379883, -6.619961261749268, 0.19982996582984924, -2.923210382461548, -5.800919532775879, -2.6428065299987793, 0.7682965397834778, -8.163551330566406, -6.404813289642334, -1.3585065603256226]
<Figure size 640x480 with 1 Axes>
def main():
train_loader, test_loader=getdata()
mnist=Mnist()
optim = paddle.optimizer.Adam(parameters=mnist.parameters()) # 设置优化器
loadmodel(mnist)
loss_fn = paddle.nn.CrossEntropyLoss() # 设置损失函数
epochs = int(input("train times:")) # 设置迭代次数
train(mnist,train_loader,epochs,optim,loss_fn)
eval(mnist,test_loader,loss_fn)
test(mnist,test_loader)
main()
data loading
data loaded not first train,loaded para
train times: 2
train begin epoch: 0, batch_id: 900, loss is: [0.06289747], acc is: [0.984375] epoch: 1, batch_id: 900, loss is: [0.01734219], acc is: [1.] saved model batch_id: 30, loss is: [0.1096139], acc is: [0.96875] batch_id: 60, loss is: [0.14677176], acc is: [0.953125] batch_id: 90, loss is: [0.05241321], acc is: [0.96875] batch_id: 120, loss is: [0.00182047], acc is: [1.] batch_id: 150, loss is: [0.07601856], acc is: [0.984375] predict: [7] label: [7] network output: [-7.678086280822754, -5.868976593017578, -4.243804454803467, -1.5573679208755493, -12.051778793334961, -5.38519811630249, -11.370020866394043, 8.172942161560059, -7.072317123413086, -3.1511974334716797]
<Figure size 640x480 with 1 Axes>
predict which line: 5
predict: [1] label: [1] network output: [-7.677154541015625, 5.846972465515137, -5.342567443847656, -5.321855545043945, -4.9580302238464355, -9.511335372924805, -6.31016206741333, -1.8860419988632202, -4.507370948791504, -9.752077102661133]
<Figure size 640x480 with 1 Axes>
predict which line: 1
predict: [2] label: [2] network output: [-8.478514671325684, -2.1858773231506348, 8.671475410461426, -1.963241457939148, -14.843521118164062, -9.429603576660156, -7.946425914764404, -9.69050121307373, -3.7265031337738037, -15.485095024108887]
<Figure size 640x480 with 1 Axes>
predict which line: q