深度学习(三)中LSTM如何应用于诗歌创作?

2026-05-19 18:561阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1739个文字,预计阅读时间需要7分钟。

深度学习(三)中LSTM如何应用于诗歌创作?

目录+数据预处理+构建数据集+模型结构+生成诗歌+基于文本生成诗歌+生成藏头诗+参考+数据前文生成诗歌:机器学习+业务,神圣不可求。临帖辞藻计,信心尽封锁。天籽咨询两,章节应四方。自述

目录
  • 数据预处理
  • 构建数据集
  • 模型结构
  • 生成诗
    • 根据上文生成诗
    • 生成藏头诗
  • 参考

  1. 根据前文生成诗:

    机器学习业,圣贤不可求。临戎辞蜀计,忠信尽封疆。天子咨两相,建章应四方。自疑非俗态,谁复念鹪鹩。

  2. 生成藏头诗:

    发初生光,三乘如太白。
    去冥冥没,冥茫寄天海。
    书三十年,手把棼琴策。
    罢华省郎,忧人惜凋病。

环境:

  • python:3.9.7
  • pytorch:1.11.0
  • numpy:1.21.2

代码地址:github.com/xiaohuiduan/deeplearning-study/tree/main/写诗

数据预处理

数据集文件由3部分组成:ix2wordword2ixdata

  • ix2word:id到word的映射,如{23:'姑'},一共有8293个word。
  • word2ix2:word到id的映射,如{'姑':23}
  • data:保存了诗的数据,一共有57580首诗,每条数据由125个word构成;如果诗的长度大于125则截断,如果诗的长度小于125,则使用""进行填充。

每条数据的构成规则为:</s></s></s>\(\dots\)<START>诗词<EOP>

在训练的时候,不考虑填充数据,因此,将数据中的填充数据</s>去除,去除后,部分数据显示如下:

构建数据集

模型输入输出决定了数据集怎么构建,下图是模型的输入输出示意图。诗词生成实际上是一个语言模型,我们希望Model能够根据当前输入\(x_0,x_1,x_2\dots x_{n-1}\)去预测下一个状态\(x_n\)。如图中所示例子,则是希望在训练的过程中,模型能够根据输入<START>床前明月光生成床前明月光,

因此根据“<START>床前明月光,凝是地上霜。举头望明月,低头思故乡<EOP>”,可以生成如下的X和Y(seq_len=6)。

X:<START>床前明月光,Y:床前明月光,

X:,凝是地上霜,Y:凝是地上霜。

X:。举头望明月,Y:举头望明月,

X:,低头思故乡,Y:低头思故乡。

代码示意图如下所示,seq_len代表每条训练数据的长度。

seq_len = 48 X = [] Y = [] poems_data = [j for i in poems for j in i] # 将所有诗的内容变成一个一维数组 for i in range(0,len(poems_data) - seq_len -1,seq_len): X.append(poems_data[i:i+seq_len]) Y.append(poems_data[i+1:i+seq_len+1]) 模型结构

模型结构如下所示,模型一共由3部分构成,Embedding层,LSTM层和全连接层。输入数据首先输入Embedding层,进行word2vec,然后将Word2Vec后的数据输入到LSTM中,最后将LSTM的输出输入到全连接层中得到预测结果。

模型构建代码如下,其中在本文中embedding_dim=200,hidden_dim=1024

import torch import torch.nn.functional as F import torch.nn as nn class PoemNet(nn.Module): def __init__(self, vocab_size, embedding_dim, hidden_dim): """ vocab_size:训练集合字典大小(8293) embedding_dim:word2vec的维度 hidden_dim:LSTM的hidden_dim """ super(PoemNet, self).__init__() self.hidden_dim = hidden_dim self.embeddings = nn.Embedding(vocab_size, embedding_dim) self.lstm = nn.LSTM(embedding_dim, self.hidden_dim,batch_first=True) self.fc = nn.Sequential( nn.Linear(self.hidden_dim,2048), nn.ReLU(), nn.Dropout(0.25), nn.Linear(2048,4096), nn.Dropout(0.2), nn.ReLU(), nn.Linear(4096,vocab_size), ) def forward(self, input,hidden=None): """ input:输入的诗词 hidden:在生成诗词的时候需要使用,在pytorch中,如果不指定初始状态h_0和C_0,则其 默认为0. pytorch的LSTM的输出是(output,(h_n,c_n))。实际上,output就是h_1,h_2,……h_n """ embeds = self.embeddings(input) batch_size, seq_len = input.size() if hidden is None: output, hidden = self.lstm(embeds) else: # h_0,c_0 = hidden output, hidden = self.lstm(embeds,hidden) output = self.fc(output) output = output.reshape(batch_size * seq_len, -1) output = F.log_softmax(output,dim=1) return output,hidden

优化器使用的是Adam优化器,lr=0.001,损失函数是CrossEntropyLoss。训练次数为100个epcoh。

生成诗

因为在模型构建的过程中,使用了dropout,所以在模型使用的时候,需要将model设置为eval模式。

生成诗的逻辑图:

根据上文生成诗

根据上图的原理,写出的代码如下所示:

深度学习(三)中LSTM如何应用于诗歌创作?

def generate_poem(my_words,max_len=128): ''' 根据前文my_words生成一首诗。max_len表示生成诗的最大长度。 ''' def __generate_next(idx,hidden=None): """ 根据input和hidden输出下一个预测 """ input = torch.Tensor([idx]).view(1,1).long().to(device) output,hidden = my_net(input,hidden) return output,hidden # 初始化hidden状态 output,hidden = __generate_next(word2ix["<START>"]) my_words_len = len(my_words) result = [] for word in my_words: result.append(word) # 积累hidden状态(h & c) output,hidden = __generate_next(word2ix[word],hidden) _,top_index = torch.max(output,1) word = idx2word[top_index[0].item()] result.append(word) for i in range(max_len-my_words_len): output,hidden = __generate_next(top_index[0].item(),hidden) _,top_index = torch.max(output,1) if top_index[0].item() == word2ix['<EOP>']: # 如果诗词已经预测到结尾 break word = idx2word[top_index[0].item()] result.append(word) return "".join(result) generate_poem("睡觉")

睡觉寒炉火,晨钟坐中朝。炉烟沾煖露,池月静清砧。自有传心法,曾无住处传。不知尘世隔,一觉一壺秋。皎洁垂银液,浮航入绿醪。谁知旧邻里,相对似相亲。

生成藏头诗

生成藏头诗的方法与根据上文生成诗的方法大同小异。

def acrostic_poetry(my_words): def __generate_next(idx,hidden=None): """ 根据input和hidden输出下一个预测词 """ input = torch.Tensor([idx]).view(1,1).long().to(device) output,hidden = my_net(input,hidden) return output,hidden def __generate(word,hidden): """ 根据word生成一句诗(以“。”结尾的话) 如根据床生成“床前明月光,凝是地上霜。” """ generate_word = word2ix[word] sentence = [] sentence.append(word) while generate_word != word2ix["。"]: output,hidden = __generate_next(generate_word,hidden) _,top_index = torch.max(output,1) generate_word = top_index[0].item() sentence.append(idx2word[generate_word]) # 根据"。"生成下一个隐状态。 _,hidden = __generate_next(generate_word,hidden) return sentence,hidden _,hidden = __generate_next(word2ix["<START>"]) result = [] for word in my_words: sentence,hidden = __generate(word,hidden) result.append("".join(sentence)) print("\n".join(result)) acrostic_poetry("滚去读书")

滚发初生光,三乘如太白。 去去冥冥没,冥茫寄天海。 读书三十年,手把棼琴策。 书罢华省郎,忧人惜凋病。

参考
  • 简单明朗的 RNN 写诗教程 - 段小辉 - 自由互联 (cnblogs.com)
  • LSTM — PyTorch 1.11.0 documentation
  • Embedding — PyTorch 1.11.0 documentation

本文共计1739个文字,预计阅读时间需要7分钟。

深度学习(三)中LSTM如何应用于诗歌创作?

目录+数据预处理+构建数据集+模型结构+生成诗歌+基于文本生成诗歌+生成藏头诗+参考+数据前文生成诗歌:机器学习+业务,神圣不可求。临帖辞藻计,信心尽封锁。天籽咨询两,章节应四方。自述

目录
  • 数据预处理
  • 构建数据集
  • 模型结构
  • 生成诗
    • 根据上文生成诗
    • 生成藏头诗
  • 参考

  1. 根据前文生成诗:

    机器学习业,圣贤不可求。临戎辞蜀计,忠信尽封疆。天子咨两相,建章应四方。自疑非俗态,谁复念鹪鹩。

  2. 生成藏头诗:

    发初生光,三乘如太白。
    去冥冥没,冥茫寄天海。
    书三十年,手把棼琴策。
    罢华省郎,忧人惜凋病。

环境:

  • python:3.9.7
  • pytorch:1.11.0
  • numpy:1.21.2

代码地址:github.com/xiaohuiduan/deeplearning-study/tree/main/写诗

数据预处理

数据集文件由3部分组成:ix2wordword2ixdata

  • ix2word:id到word的映射,如{23:'姑'},一共有8293个word。
  • word2ix2:word到id的映射,如{'姑':23}
  • data:保存了诗的数据,一共有57580首诗,每条数据由125个word构成;如果诗的长度大于125则截断,如果诗的长度小于125,则使用""进行填充。

每条数据的构成规则为:</s></s></s>\(\dots\)<START>诗词<EOP>

在训练的时候,不考虑填充数据,因此,将数据中的填充数据</s>去除,去除后,部分数据显示如下:

构建数据集

模型输入输出决定了数据集怎么构建,下图是模型的输入输出示意图。诗词生成实际上是一个语言模型,我们希望Model能够根据当前输入\(x_0,x_1,x_2\dots x_{n-1}\)去预测下一个状态\(x_n\)。如图中所示例子,则是希望在训练的过程中,模型能够根据输入<START>床前明月光生成床前明月光,

因此根据“<START>床前明月光,凝是地上霜。举头望明月,低头思故乡<EOP>”,可以生成如下的X和Y(seq_len=6)。

X:<START>床前明月光,Y:床前明月光,

X:,凝是地上霜,Y:凝是地上霜。

X:。举头望明月,Y:举头望明月,

X:,低头思故乡,Y:低头思故乡。

代码示意图如下所示,seq_len代表每条训练数据的长度。

seq_len = 48 X = [] Y = [] poems_data = [j for i in poems for j in i] # 将所有诗的内容变成一个一维数组 for i in range(0,len(poems_data) - seq_len -1,seq_len): X.append(poems_data[i:i+seq_len]) Y.append(poems_data[i+1:i+seq_len+1]) 模型结构

模型结构如下所示,模型一共由3部分构成,Embedding层,LSTM层和全连接层。输入数据首先输入Embedding层,进行word2vec,然后将Word2Vec后的数据输入到LSTM中,最后将LSTM的输出输入到全连接层中得到预测结果。

模型构建代码如下,其中在本文中embedding_dim=200,hidden_dim=1024

import torch import torch.nn.functional as F import torch.nn as nn class PoemNet(nn.Module): def __init__(self, vocab_size, embedding_dim, hidden_dim): """ vocab_size:训练集合字典大小(8293) embedding_dim:word2vec的维度 hidden_dim:LSTM的hidden_dim """ super(PoemNet, self).__init__() self.hidden_dim = hidden_dim self.embeddings = nn.Embedding(vocab_size, embedding_dim) self.lstm = nn.LSTM(embedding_dim, self.hidden_dim,batch_first=True) self.fc = nn.Sequential( nn.Linear(self.hidden_dim,2048), nn.ReLU(), nn.Dropout(0.25), nn.Linear(2048,4096), nn.Dropout(0.2), nn.ReLU(), nn.Linear(4096,vocab_size), ) def forward(self, input,hidden=None): """ input:输入的诗词 hidden:在生成诗词的时候需要使用,在pytorch中,如果不指定初始状态h_0和C_0,则其 默认为0. pytorch的LSTM的输出是(output,(h_n,c_n))。实际上,output就是h_1,h_2,……h_n """ embeds = self.embeddings(input) batch_size, seq_len = input.size() if hidden is None: output, hidden = self.lstm(embeds) else: # h_0,c_0 = hidden output, hidden = self.lstm(embeds,hidden) output = self.fc(output) output = output.reshape(batch_size * seq_len, -1) output = F.log_softmax(output,dim=1) return output,hidden

优化器使用的是Adam优化器,lr=0.001,损失函数是CrossEntropyLoss。训练次数为100个epcoh。

生成诗

因为在模型构建的过程中,使用了dropout,所以在模型使用的时候,需要将model设置为eval模式。

生成诗的逻辑图:

根据上文生成诗

根据上图的原理,写出的代码如下所示:

深度学习(三)中LSTM如何应用于诗歌创作?

def generate_poem(my_words,max_len=128): ''' 根据前文my_words生成一首诗。max_len表示生成诗的最大长度。 ''' def __generate_next(idx,hidden=None): """ 根据input和hidden输出下一个预测 """ input = torch.Tensor([idx]).view(1,1).long().to(device) output,hidden = my_net(input,hidden) return output,hidden # 初始化hidden状态 output,hidden = __generate_next(word2ix["<START>"]) my_words_len = len(my_words) result = [] for word in my_words: result.append(word) # 积累hidden状态(h & c) output,hidden = __generate_next(word2ix[word],hidden) _,top_index = torch.max(output,1) word = idx2word[top_index[0].item()] result.append(word) for i in range(max_len-my_words_len): output,hidden = __generate_next(top_index[0].item(),hidden) _,top_index = torch.max(output,1) if top_index[0].item() == word2ix['<EOP>']: # 如果诗词已经预测到结尾 break word = idx2word[top_index[0].item()] result.append(word) return "".join(result) generate_poem("睡觉")

睡觉寒炉火,晨钟坐中朝。炉烟沾煖露,池月静清砧。自有传心法,曾无住处传。不知尘世隔,一觉一壺秋。皎洁垂银液,浮航入绿醪。谁知旧邻里,相对似相亲。

生成藏头诗

生成藏头诗的方法与根据上文生成诗的方法大同小异。

def acrostic_poetry(my_words): def __generate_next(idx,hidden=None): """ 根据input和hidden输出下一个预测词 """ input = torch.Tensor([idx]).view(1,1).long().to(device) output,hidden = my_net(input,hidden) return output,hidden def __generate(word,hidden): """ 根据word生成一句诗(以“。”结尾的话) 如根据床生成“床前明月光,凝是地上霜。” """ generate_word = word2ix[word] sentence = [] sentence.append(word) while generate_word != word2ix["。"]: output,hidden = __generate_next(generate_word,hidden) _,top_index = torch.max(output,1) generate_word = top_index[0].item() sentence.append(idx2word[generate_word]) # 根据"。"生成下一个隐状态。 _,hidden = __generate_next(generate_word,hidden) return sentence,hidden _,hidden = __generate_next(word2ix["<START>"]) result = [] for word in my_words: sentence,hidden = __generate(word,hidden) result.append("".join(sentence)) print("\n".join(result)) acrostic_poetry("滚去读书")

滚发初生光,三乘如太白。 去去冥冥没,冥茫寄天海。 读书三十年,手把棼琴策。 书罢华省郎,忧人惜凋病。

参考
  • 简单明朗的 RNN 写诗教程 - 段小辉 - 自由互联 (cnblogs.com)
  • LSTM — PyTorch 1.11.0 documentation
  • Embedding — PyTorch 1.11.0 documentation