带自己学paddle(五)

项目一 手写数字识别

上文回顾,目前已经揭晓了l2正则化以及如何画图,这一章主要是为了重构代码,代码断点重续、增加动态图转静态图的操作,这两块将合并起来一起写,不多说,先上代码
network.py

from paddle.nn.layer import Conv2D,MaxPool2D,Linear
import paddle.nn.functional as F
class MNIST(paddle.nn.Layer):
	def __init__(self):
		super(MNIST,self).__init__()
		nn.initializer.set_global_initializer(nn.initializer.Uniform(),nn.initializer.Constant())
		# 卷积层
		self.conv1=Conv2D(in_channels=1,out_channels=20,kernel_size=5,padding=2)
		# 池化层
		self.max_pool1=MaxPool2D(kernel_size=2,stride=2)
		# 卷积层
		self.conv2=Conv2D(in_channels=20,out_channels=20,kernel_size=5,padding=2)
		# 池化层
		self.max_pool2=MaxPool2D(kernel_size=2,stride=2)
		#线性层
		self.fc=Linear(in_features=980,out_features=10)
	
	# 新增一个装饰器,使得动态图网络结构在静态图模式下运行
	@paddle.jit.to_static
	def forward(self,inputs):
		x=self.conv1(inputs)
		x=F.relu()
		x=self.max_pool1(x)
		x=self.conv2(x)
		x=F.relu()
		x=self.max_pool2(x)
		x=paddle.reshape(x,[x.shape[0],980])
		x=self.fc(x)
		return x

动态图转静态图是对网络的forward函数进行操作,其目的是为后续部署做好模型转换的准备

trainer.py
这里的设计思路是,首先这个Trainer接收的是模型的保存路径,模型初始化以及优化器等,然后这个类包含以下功能:

  1. 训练每个batch的逻辑函数
  2. epoch函数管理
  3. 对每个epoch所产生的模型进行保存
  4. 保存模型函数(保存中间变量以及包含模型参数)
import paddle
import paddle.nn.functional as F
import os

class Trainer(object):
	def __init__(self,model_path,model,optimizer):
		self.model_path=model_path
		self.model=model
		self.optimizer=optimizer
	
	def save(self):
		paddle.save(self.model.state_dict(),self.model_path)
	
	def norm_img(img):
		batch_size=img.shape[0]
		img=img/127.5-1
		img=paddle.reshape(img,[batch_size,784])
		return img
	
	def train_step(self,data):
		images=self.norm_img(data[0]).astype('float32')
		labels=data[1].astype('int64')
		predicts=self.model(images)
		loss=F.cross_entropy(predicts,labels)
		avg_loss=paddle.mean(loss)
		avg_loss.backward()
		self.optimizer.step()
		self.optimizer.clear_grad()
		return avg_loss
	
	def train_epoch(self,datasets,epoch):
		self.model.train()
		for batch_id,data in enumerate(datasets()):
			loss=self.train_step(data)
			if batch_id % 500 ==0:
				print('epoch_id:{}, batch_id: {} loss is :{}'.format(epoch,batch_id,loss.numpy()))
	
	def train(self,train_datasets,start_epoch,end_epoch,save_path):
		if not os.path.exists(save_path):
			os.makedirs(save_path)
		for i in range(start_epoch,end_epoch):
			self.train_epoch(train_datasets,i)
			paddle.save(self.optimizer.state_dict(),'./{}/mnist_epoch{}'.format(save_path,i)+".pdopt"
			paddle.save(self.model.state_dict(),'./{}/mnist_epoch{}',format(save_path,i)+".pdparams")
		self.save()
			
			

测试代码

import paddle

use_gpu=True
paddle.set_device("gpu:0") if use_gpu else paddle.set_device("cpu")

import warnings
warnings.filterwarnings('ignore')
paddle.seed(1024)

epochs=3
BATCH_SIZE=32
model_path='./mnist_pdparams'
paddle.vision.set_image_backend('cv2')
train_dataset=paddle.io.DataLoader(paddle.vision.datasets.MNIST(mode='train'),batch_size=16,shuffle=True)

model=MNIST()
total_steps=(int(50000//BATCH_SIZE)+1)*epochs
lr=paddle.optimizer.lr.PolynomialDecay(learning_rate=lr,parameters=model.parameters())
opt=paddle.optimizer.Momentum(learning_rate=lr,parameters=model.parameters())
trainer=Trainer(model_path=model_path,model=model,optimizer=opt)
trainer.train(train_datasets=train_loader,start_epoch=0,end_epoch=epochs,save_path='checkpoint')

然后训练完成后,会生成这些断点模型
带自己学paddle(五)_第1张图片
然后这里如果要进行断点训练,可进行如下操作

import paddle
import warnings
warnings.filterwarnings('ignore')
paddle.seed(1024)
epochs=3
BATCH_SIZE=32
total_steps=(int(50000//BATCH_SIZE)+1)*epochs
lr=paddle.optimizer.lr.PolynomialDecay(learning_rate=lr,parameters=model.parameters())
opt=paddle.optimizer.Momentum(learning_rate=lr,parameters=model.parameters())
'''导入断点权重'''
param_dict=paddle.load('./checkpoint/mnist_epoch0.pdparams')
opt_dict=paddle.load('./checkpoint/mnist_epoch0.pdopt')
model.set_state_dict(param_dict)
opt.set_state_dict(opt_dict)

trainer=Trainer(model_path=model_path,model=model,optimizer=opt)
trainer.train(train_datasets=train_loader,start_epoch=0,end_epoch=epochs,save_path='checkpoint')

在推理&部署场景中,需要同时保存推理模型的结构和参数,但是动态图是即时执行即时得到结果,并不会记录模型的结构信息。动态图在保存推理模型时,需要先将动态图模型转换为静态图写法,编译得到对应的模型结构再保存,而飞桨框架2.0版本推出paddle.jit.save和paddle.jit.load接口,无需重新实现静态图网络结构,直接实现动态图模型转成静态图模型格式。

然后这里如果要进行动态转静态,然后进行推理可以进行如下两步

  1. 动态图转静态图(这里的情况是,万一模型本身没有加paddle.jit.to_static())的修饰,用这代码块进行转换
model=MNIST()
state_dict=paddle.load('./mnist.pdparams')
model.set_state_dict(state_dict) # 将训练好的参数读取到网络中
model.eval()
paddle.jit.save(layer=model,path='inference/mnist',input_spec=[InputSpec(shape=[None,784],dtype='float32')])

这是时候,会自动生成inference文件夹,然后把模型存的这里
在这里插入图片描述
具体包括三种文件:保存模型结构的*.pdmodel文件;保存推理用参数的*.pdiparams文件和保存兼容变量信息的*.pdiparams.info文件,这几个文件后缀均为paddle.jit.save保存时默认使用的文件后缀。
2. 推理

	import paddle
import numpy as np
import paddle.nn.functional as F


def norm_img(img):
    batch_size=img.shape[0]
    img=img/127.5-1
    img=paddle.reshape(img,[batch_size,784])
    return img

paddle.vision.set_image_backend('cv2')

mnist_test=paddle.vision.datasets.MNIST(mode='test')
test_image,label=mnist_test[1]
print('The label of readed image is:',label)
test_image=paddle.reshape(paddle.to_tensor(test_image),[1,784])
test_image=norm_img(test_image)
loaded_model=paddle.jit.load('./inference/mnist')
preds=loaded_model(test_image)
pred_label=paddle.argmax(preds)
print('The predicted label is:',pred_label.numpy())

结果:

The predicted label is: [2]
The label of readed image is: [2]

你可能感兴趣的:(paddle,paddle,计算机视觉)