使用序列到序列模型完成数字加法
日期: 2021.01
摘要: 本示例教程介绍如何使用飞桨完成一个数字加法任务,我们将会使用飞桨提供的LSTM的API,组建一个序列到序列模型,并在随机生成的数据集上完成数字加法任务的模型训练与预测。
本教程基于Paddle 2.0 编写,如果您的环境不是本版本,请先参考官网 Paddle 2.0 。
二、构建数据集
随机生成数据,并使用生成的数据构造数据集
通过继承
paddle.io.Dataset
来完成数据集的构造
generating datas..
making the dataset...
finish
本次介绍的模型是一个简单的基于
LSTM
的Seq2Seq
模型一共有如下四个主要的网络层:
嵌入层(
Embedding
):将输入的文本序列转为嵌入向量编码层(
LSTM
):将嵌入向量进行编码解码层(
LSTM
):将编码向量进行解码
损失函数为交叉熵损失函数
四、模型训练与评估
使用
Adam
作为优化器进行模型训练以模型准确率作为评价指标
使用
VisualDL
对训练数据进行可视化训练过程中会同时进行模型评估和最佳模型的保存
# 初始化log写入器
log_writer = LogWriter(logdir="./log")
# 模型参数设置
embedding_size = 128
hidden_size=128
num_layers=1
# 训练参数设置
epoch_num = 50
learning_rate = 0.001
log_iter = 2000
eval_iter = 500
# 定义一些所需变量
global_step = 0
log_step = 0
max_acc = 0
# 实例化模型
model = Addition_Model(
char_len=len(label_dict),
embedding_size=embedding_size,
num_layers=num_layers,
DIGITS=DIGITS)
# 将模型设置为训练模式
model.train()
opt = paddle.optimizer.Adam(
learning_rate=learning_rate,
parameters=model.parameters()
)
# 启动训练,循环epoch_num个轮次
for epoch in range(epoch_num):
# 遍历数据集读取数据
for batch_id, data in enumerate(train_reader()):
# 读取数据
inputs, labels = data
# 模型前向计算
loss, acc = model(inputs, labels=labels)
# 打印训练数据
if global_step%log_iter==0:
print('train epoch:%d step: %d loss:%f acc:%f' % (epoch, global_step, loss.numpy(), acc.numpy()))
log_writer.add_scalar(tag="train/loss", step=log_step, value=loss.numpy())
log_writer.add_scalar(tag="train/acc", step=log_step, value=acc.numpy())
log_step+=1
# 模型验证
if global_step%eval_iter==0:
model.eval()
losses = []
accs = []
for data in dev_reader():
loss, acc = model(inputs, labels=labels)
losses.append(loss.numpy())
accs.append(acc.numpy())
avg_loss = np.concatenate(losses).mean()
avg_acc = np.concatenate(accs).mean()
print('eval epoch:%d step: %d loss:%f acc:%f' % (epoch, global_step, avg_loss, avg_acc))
log_writer.add_scalar(tag="dev/loss", step=log_step, value=avg_loss)
log_writer.add_scalar(tag="dev/acc", step=log_step, value=avg_acc)
# 保存最佳模型
if avg_acc>max_acc:
max_acc = avg_acc
paddle.save(model.state_dict(), 'best_model')
model.train()
# 反向传播
loss.backward()
# 使用优化器进行参数优化
opt.step()
# 清除梯度
opt.clear_grad()
# 全局步数加一
global_step += 1
# 保存最终模型
paddle.save(model.state_dict(),'final_model')
- 使用保存的最佳模型进行测试
# 反转字符表
label_dict_adv = {v: k for k, v in label_dict.items()}
# 输入计算题目
input_text = '12+40'
# 编码输入为ID
inputs = encoder(input_text, MAXLEN, label_dict)
# 转换输入为向量形式
inputs = np.array(inputs).reshape(-1, MAXLEN)
inputs = paddle.to_tensor(inputs)
# 加载模型
params_dict= paddle.load('best_model')
model.set_dict(params_dict)
# 设置为评估模式
model.eval()
# 模型推理
out = model(inputs)
# 结果转换
result = ''.join([label_dict_adv[_] for _ in np.argmax(out.numpy(), -1).reshape(-1)])
# 打印结果
print('the model answer: %s=%s' % (input_text, result))
print('the true answer: %s=%s' % (input_text, eval(input_text)))
六、总结
同时,也可以尝试在其他的类似的任务中用飞桨来完成实际的实践