# 简单明朗的 RNN 写诗教程
![](https://www.writebug.com/myres/static/uploads/2021/12/8/d845ae36add5348afc5f6a40ed471a9f.writebug)
## 数据集介绍
既然是写诗,当然得有数据集,不过还好有大神已经将数据集准备好了,具体数据集的来源已不可知,因为网上基本上都是使用这个数据集。*(如果有人知道,可以指出,然后我再添加上)*
数据集地址:[Github](https://github.com/xiaohuiduan/rnn_chinese_poetry/blob/main/data/poetry.txt),数据集部分数据如下所示:
![](https://www.writebug.com/myres/static/uploads/2021/12/8/7c334cc99ed0dcec589b29f3436a8118.writebug)
在数据集中,**每一行**都是一首唐诗,其中,诗的题目和内容以 **":"** 分开,每一首诗都有题目,但是不一定有内容(也就是说内容可能为空)。其中,诗内容中的标点符号都是**全角符号**。有一些诗五言诗,不过也有一些诗不是五言的。当然,我们只考虑**五言诗**(大概有 27k 首)。
## 代码思路
### 输入 and 输出
首先我们得先弄清我们要干什么,然后才能更好得写代码。如标题所示,目的是使用 RNN 写诗,那么必然有输入和输出。那么问题来了,RNN 的输入是什么,输出是什么?
我们希望 rnn 能够写诗,那么怎么写呢?我们这样定义如下的方式:
![](https://www.writebug.com/myres/static/uploads/2021/12/8/f26ce770aa3730c699d4a81d441213fc.writebug)
RNN 接受 **6 个字符**(5 个字 + 一个标点符号),然后输出下一个字符。至于怎么生成一首完整的诗词,等到后面讨论。
RNN 当然不能够直接接受 "床前明月光," 这个中文的输入,我们要对其进行 Encode,变成数字,然后才能够输入到 RNN 网络中。同理,RNN 输出的肯定也不是一个中文字符,我们也要对其进行 Decode 才能将输出变成一个中文字符。
怎么进行 Encode,有一个很简单的方法,那就是进行 **one-hot** 编码,对于每一个字(包括标点符号在内)我们都进行 onehot 编码,这样就可以了。但实际上,这个这样会有一点小问题。在数据集中,所有符合条件的诗,大概由近 **7,000** 个字符组成,如果对每一个字都进行 onehot 编码的话,就会消耗大量的内存,同时也会加大计算的复杂度。
因此,我们定义如下:只对前出现频率最多的 **2999** 个字符进行 one-hot 编码,对于剩下的字,用 **“ ”**(空格字符)代替。这样一共只需要对 3000 个字符进行 one-hot 编码就了(2999 个字符 + 一个空格字符)。
![](https://www.writebug.com/myres/static/uploads/2021/12/8/66d8dce59dca251f5d8cdccd79959324.writebug)
### 训练集构建
在前面我们定义了 RNN 的输入和输出,同时也有诗的数据集, 那么我们构建**训练集**呢?参考 [RNN 模型与 NLP 应用(6/9):Text Generation (自动文本生成)](https://www.youtube.com/watch?v=10cjvcrU_ZU&list=PLvOO0btloRnuTUGN4XqO85eKPeFSZsEqK&index=6&ab_channel=ShusenWang)
具体步骤如下图所示:我们将一句诗可以进行如下切分。然后将切分得到的数据进行 one-hot 编码,然后进行训练即可。(这样看来,每一首诗可以生成很多的数据集)
![](https://www.writebug.com/myres/static/uploads/2021/12/8/aae921fa4df9f2c0190a6935d5ab6fe6.writebug)
### 生成一首完整的诗
前面我们讨论了关于网络的输入和输出,以及数据集的构建,那么,假如我们有一个已经训练好的模型,如何来产生一首诗的?
生成一首完整的诗的流程如下所示,与训练的操作有点类似,只不过会将 RNN 的输出重新当作 RNN 的输入。(以此来产生符合字数要求的诗)
![](https://www.writebug.com/myres/static/uploads/2021/12/8/f1fa9d46343174707be79d1d388c636e.writebug)
经过上述的操作,大家实际上可以尝试的写一些代码了,基本上不会有很大的问题。接下来,我将讲一讲具体怎么实现。
## 代码实现
首先定义一些配置:
- DISALLOWED_WORDS:如果在诗中出现了 **DISALLOWED_WORDS**,则舍弃这首诗。
```python
# 诗data的地址
poetry_data_path = "./data/poetry.txt"
# 如果诗词中出现这些词,则将诗舍弃
DISALLOWED_WORDS = ['(', ')', '(', ')', '__', '《', '》', '【', '】', '[', ']']
# 取3000个字作诗,其中包括空格字符
WORD_NUM = 3000
# 将出现少的字使用空格代替
UNKONW_CHAR = " "
# 根据前6个字预测下一个字,比如说根据“寒随穷律变,”预测“春”
TRAIN_NUM = 6
```
### 读取文件
针对于数据集,我们有如下的要求:
- 必须是**五言诗**(不过下面的代码无法完全保证是五言诗),同时至少要有**两句诗**
- 不能出现上文中定义的 DISALLOWED_WORDS
前面我们说了,每一首诗必有题目和内容(内容可以为空),其中,题目和内容以 ":"(半角)分开,因此,我们可以通过 `line.split(":")[1]` 获得诗的内容。
下述代码实现了两个功能:
1. 获得符合要求的诗:`(len(poetry)-1) % 6`,每一首五言诗,包括“,。”一共有 $6*n$ 个字,同时每一首诗是以 "\n" 结尾的,因为我们 ``(len(poetry)-1)%6==0`` 则就代表符合要求。同时五言诗的第 6 个字符是","——> 使用 `poetrys` 保存。
2. 获得诗中出现的字符。——> 使用 `all_word` 保存。
```python
# 保存诗词
poetrys = []
# 保存在诗词中出现的字
all_word = []
with open(poetry_data_path,encoding="utf-8") as f:
for line in f:
# 获得诗的内容
poetry = line.split(":")[1].replace(" ","")
flag = True
# 如果在句子中出现'(', ')', '(', ')', '__', '《', '》', '【', '】', '[', ']'则舍弃
for dis_word in DISALLOWED_WORDS:
if dis_word in poetry:
flag = False
break
# 只需要5言的诗(两句诗包括标点符号就是12个字),假如少于两句诗则舍弃
if len(poetry) < 12 or poetry[5] != ',' or (len(poetry)-1) % 6 != 0:
flag = False
if flag:
# 统计出现的词
for word in poetry:
all_word.append(word)
poetrys.append(poetry)
```
![](https://www.writebug.com/myres/static/uploads/2021/12/8/c4f13daaac6163b98c1b80be6c98db35.writebug)
### 统计字数
前面我们说过,在数据集中,所有符合条件的诗,大概由近 **7,000** 个字组成,如果对每一个字都进行 one-hot 编码的话,就会浪费大量的内存,加大计算的复杂度。解决方法可以这样做:
> 使用 Counter 对字数进行统计,然后根据出现的次数进行排序,最后得到出现频率最多的 2999 个字。
```python
from collections import Counter
# 对字数进行统计
counter = Counter(all_word)
# 根据出现的次数,进行从大到小的排序
word_count = sorted(counter.items(),key=lambda x : -x[1])
most_num_word,_ = zip(*word_count)
# 取前2999个字,然后在最后加上" "
use_words = most_num_word[:WORD_NUM - 1] + (UNKONW_CHAR,)
```
![](https://www.writebug.com/myres/static/uploads/2021/12/8/f2d96c304bcf763fb344906f960254d2.writebug)
### 构建 word 与 id 的映射
我们需要对 word 进行 onehot 编码,怎么编呢?很简单,每一个 word 对应一个 id,然后对这个 id 进行 one-hot 编码就行了。因此我们需要构建 word 到 id 的映射。
> 举个例子:如果一共只有 3 个字“唐”,“宋”,“明”,然后我们可以构建如下的映射:
>
> "唐" ——> 0 ;"宋"——>1;"明"——>2;进行 one-hot 编码后,则就变成了:
>
> - 唐:[1,0,0]
> - 宋:[0,1,0]
> - 明:[0,0,1]
构建 word 与 id 的映射是必须的,经过如下简单的代码,便构成了映射。
```python
# word 到 id�
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
使用 keras 模型构建一个 RNN 模型,然后使用其来自动生成五言诗。在数据集中,每一行都是一首唐诗,其中,诗的题目和内容以 ":" 分开,每一首诗都有题目,但是不一定有内容(也就是说内容可能为空)。
资源推荐
资源详情
资源评论
收起资源包目录
100012734-基于Python RNN模型实现自动生成五言诗.zip (24个子文件)
rnnpoem
test.ipynb 6KB
poetry_model.hdf5 31.7MB
data
poetry.txt 9.71MB
LICENSE 1KB
main.ipynb 11KB
out
out.txt 4KB
rnn_poetry_model.png 242KB
imgs
RNN_one-hot-io-1611562307620.svg 16KB
rnn_poetry.jpg 36KB
create_whole_poem.svg 39KB
RNN_split_data.svg 22KB
rnn-many-to-many-same-ltr.png 10KB
rnn-many-to-one-ltr.png 8KB
image-20210125200034659.png 15KB
rnn_io.svg 7KB
image-20210126123029328.png 214KB
image-20210125203730771.png 34KB
image-20210125151810940.png 1001KB
rnn_poetry_model.png 84KB
image-20210125195532009.png 54KB
image-20210125200115940.png 17KB
image-20210125203759955.png 32KB
image-20210125204257815.png 62KB
README.md 19KB
共 24 条
- 1
资源评论
- m0_709725282024-04-23资源内容总结的很到位,内容详实,很受用,学到了~
- 如果热过若干2023-12-21这个资源值得下载,资源内容详细全面,与描述一致,受益匪浅。
神仙别闹
- 粉丝: 2679
- 资源: 7667
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功