热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【PyTorch】基于自然语言处理和长短期记忆网络的“AI诗人”

目录长短期记忆网络(LSTM)自然语言处理之词嵌入(WordEmbedding)get_data.py-数据预处理model.py-定义神经网络模型train.py-训练神经网络一

目录

  • 长短期记忆网络 (LSTM)
  • 自然语言处理之词嵌入 (Word Embedding)
  • get_data.py - 数据预处理
  • model.py - 定义神经网络模型
  • train.py - 训练神经网络
  • 一些比较好的AI生成诗句


长短期记忆网络 (LSTM)

长短期记忆网络 (Long Short-Term Memory, LSTM) 是循环神经网络 (Recurrent Neural Network, RNN) 的一种变体。RNN存在梯度消失 (vanishing gradient) 或梯度爆炸 (exploding gradient) 问题,所以尽管很多问题对RNN是适用的,但实际上并不能应用于解决这些问题。而LSTM的提出改变了这一情况。
在RNN中,网络会“记住”一切,但人类的大脑却并不是这样的。LSTM引入了遗忘门,随着在输入链中不断深入,输入链开始的部分会变得不那么重要。单元最后会成为网络层的“记忆”,而输入门、输出门和遗忘门会确定数据如何经过一个网络层。
这是经典RNN的结构示意图及其结构展开示意图:
RNN
展开的RNN
这是LSTM的结构示意图:
LSTM

自然语言处理之词嵌入 (Word Embedding)

我们应该如何在一个神经网络中表示一个词?最简单的方法是使用独热编码 (one-hot encoding) 。独热编码会根据词的规模创建一个张量,对其中的每个词分配一个向量,每个向量中有一个元素会被设置为1,其余元素会被设置为0。比如我们有这样一个句子:I like eating apple.,则我们可以得到一个单词表["I", "like", "eating", "apple"],每个词的向量为:

I -> [1 0 0 0]
like -> [0 1 0 0]
eating -> [0 0 1 0]
apple -> [0 0 0 1]

独热编码虽然简单,但也有很多限制与不足。比如我们要向单词表中再增加一个词,由于编码机制就要修改所有的词向量。再如,有些词语之间是有一定联系的(比如puppydog),显然,独热编码不能表示词与词之间的关系。此外,独热编码的绝大部分元素都是0,只有一个元素会被设置为1,这也造成了内存的浪费。
嵌入矩阵解决了独热编码的这些缺陷。其实独热编码本质上也是一个嵌入矩阵,但它不包含词与词之间关系的信息。嵌入矩阵的思想是压缩向量空间的维度,从而充分利用这个空间。在向量空间中,类似的词会被聚集在一起,这样就可以通过词与词之间的“距离”来度量其接近程度。嵌入层和神经网络的其他层的训练过程没有什么区别,即随机初始化向量空间,在训练过程中更新参数,使得类似的词的距离更加接近。
在PyTorch中使用嵌入层非常简单:

import torch.nn as nn# 使用嵌入层
embed = nn.Embedding(vocab_size, dimension_size)

嵌入层包含一个随机初始化的vocab_size * dimension_size的张量,单词表中的每个词会索引到这个张量中的一个元素,每个元素是一个大小为dimension_size的向量。

get_data.py - 数据预处理

数据集来自于GitHub上中文爱好者收集的5万多首唐诗,经过数据处理后打包成为一个NumPy压缩包tang.npz,加载后是一个57580 * 125的NumPy数组。
GitHub链接
tang.npz下载链接(提取码:a5gg)

import osimport numpy as npdef get_data(data_path):if os.path.exists(data_path):datas = np.load(data_path, allow_pickle=True)data = datas['data']word2ix = datas['word2ix'].item()ix2word = datas['ix2word'].item()print('The data is loaded successfully.')return data, word2ix, ix2wordelse:print('[ERROR]No such file was found or the specified path name doesn\'t exist.')exit(-1)
model.py - 定义神经网络模型

import torch
import torch.nn as nn
from torch.autograd import Variableclass LSTM(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim):super(LSTM, self).__init__()self.hidden_dim = hidden_dimself.embedding = nn.Embedding(vocab_size, embedding_dim)self.lstm = nn.LSTM(embedding_dim, self.hidden_dim, num_layers=2, batch_first=False)self.linear = nn.Linear(self.hidden_dim, vocab_size)def forward(self, input_, hidden=None):seq_len, batch_size = input_.size()if hidden is None:h_0 = input_.data.new(2, batch_size, self.hidden_dim).fill_(0).float()c_0 = input_.data.new(2, batch_size, self.hidden_dim).fill_(0).float()h_0, c_0 = Variable(h_0), Variable(c_0)else:h_0, c_0 = hiddenembed = self.embedding(input_)output, hidden = self.lstm(embed, (h_0, c_0))output = self.linear(output.reshape(seq_len * batch_size, -1))return output, hidden

train.py - 训练神经网络

import os
import tqdmfrom sklearn.model_selection import train_test_split
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoaderfrom get_data import get_data
from model import LSTMif not os.path.exists('./model/'):os.mkdir('./model/')DATA_PATH = './data/tang.npz'
BATCH_SIZE = 64
LEARNING_RATE = 1e-3
EMBEDDING_DIM = 128
HIDDEN_DIM = 256
EPOCH = 50device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print('[LSTM model is being trained using the {}]'.format('GPU' if torch.cuda.is_available() else 'CPU'))data, word2ix, ix2word = get_data(DATA_PATH)
_, data_eval = train_test_split(data, train_size=0.8, random_state=1)
data_train, data_eval = torch.from_numpy(data), torch.from_numpy(data_eval)
data_loader_train = DataLoader(data_train, batch_size=BATCH_SIZE, shuffle=True)
data_loader_eval = DataLoader(data_eval, batch_size=BATCH_SIZE, shuffle=True)model = LSTM(len(word2ix), EMBEDDING_DIM, HIDDEN_DIM).to(device)
# model.load_state_dict(torch.load('./model/LSTM.pth', map_location=device))
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE, betas=(0.9, 0.999), eps=1e-8)
criterion = nn.CrossEntropyLoss()for epoch in range(1, EPOCH + 1):train_loss = 0train_step = 0model.train()for i, data in tqdm.tqdm(enumerate(data_loader_train)):data = data.long().transpose(0, 1).contiguous().to(device)optimizer.zero_grad()input_, target = Variable(data[:-1, :]), Variable(data[1:, :])output, _ = model(input_)loss = criterion(output, target.view(-1))loss.backward()optimizer.step()train_loss += loss.item()train_step += 1eval_loss = 0eval_step = 0model.eval()for i, data in tqdm.tqdm(enumerate(data_loader_eval)):data = data.long().transpose(0, 1).contiguous().to(device)input_, target = Variable(data[:-1, :]), Variable(data[1:, :])output, _ = model(input_)loss = criterion(output, target.view(-1))eval_loss += loss.item()eval_step += 1print('[{:2d}/{:2d}] Train Loss: {:6.4f} | Eval Loss: {:6.4f}'.format(epoch, EPOCH, train_loss / train_step,eval_loss / eval_step))torch.save(model.state_dict(), './model/LSTM_epoch{}.pth'.format(epoch))
print('Training completed.')

上面代码中的第18-23行是网络训练的一些参数,可以根据自己的实际情况手动调节。我在训练中采取的策略是每次将EPOCH设置为一个较小的数字(比如20或50),选定一个合适的LEARNING_RATE进行训练,并且保存每轮训练后的模型参数。一次训练结束后,可以考虑在下一次训练中加载预训练的LSTM.pth参数并且调整LEARNING_RATE进行训练。

一些比较好的AI生成诗句
  • 里巷风尘起,南山杨柳深。
  • 不堪捎落叶,空想抱秋心。
  • 十日花落尽,一朝春景浓。
  • 远期千里别,明日一时愁。
  • 如闻北斗月,又见南山泉。
  • 心事不可得,无心亦无疑。
  • 永日无人见,春风不自由。
  • 远山开旧岭,清净入深州。

推荐阅读
  • 关于如何快速定义自己的数据集,可以参考我的前一篇文章PyTorch中快速加载自定义数据(入门)_晨曦473的博客-CSDN博客刚开始学习P ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • Learning to Paint with Model-based Deep Reinforcement Learning
    本文介绍了一种基于模型的深度强化学习方法,通过结合神经渲染器,教机器像人类画家一样进行绘画。该方法能够生成笔画的坐标点、半径、透明度、颜色值等,以生成类似于给定目标图像的绘画。文章还讨论了该方法面临的挑战,包括绘制纹理丰富的图像等。通过对比实验的结果,作者证明了基于模型的深度强化学习方法相对于基于模型的DDPG和模型无关的DDPG方法的优势。该研究对于深度强化学习在绘画领域的应用具有重要意义。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • OCR:用字符识别方法将形状翻译成计算机文字的过程Matlab:商业数学软件;CUDA:CUDA™是一种由NVIDIA推 ... [详细]
  • 程序分析与优化9附录XLA的缓冲区指派
    本章是系列文章的案例学习,不属于正篇,主要介绍了TensorFlow引入的XLA的优化算法。XLA也有很多局限性,XLA更多的是进行合并,但有时候如果参数特别多的场景下,也需要进行 ... [详细]
  • 干货 | 携程AI推理性能的自动化优化实践
    作者简介携程度假AI研发团队致力于为携程旅游事业部提供丰富的AI技术产品,其中性能优化组为AI模型提供全方位的优化方案,提升推理性能降低成本࿰ ... [详细]
  • 用c语言实现线画、填充图元生成算法多边形_【游戏场景剔除】剔除算法综述...
    之前在做场景优化的过程中,看了不少论文和博客阐述不同剔除算法的原理和过程,自己参照着算法去实现了Hiz和软件剔除。一直想写一篇关于剔除算法的综述 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 技嘉秀高端B450主板:不再支持第七代APU,性价比高且兼容锐龙一代和二代
    在台北电脑展上,技嘉展示了一款高端的B450主板,型号为“b450 aorus pro wi-fi”。该主板具有10+1相供电、散热片覆盖的供电区域和芯片组,以及两个m.2插槽和背部IO挡板。虽然不支持第七代APU bristol ridge,但它兼容锐龙一代和二代,且具有较高的性价比。该主板还配备了音频声卡、Wi-Fi无线网卡等功能,是一款性能出色且设计精良的主板。 ... [详细]
author-avatar
JohnBeanLee
A PHP Coder
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有