一、实验要求
用 Pytorch 模块的 RNN 实现生成唐诗。要求给定一个字能够生成一首唐诗。
二、实验目的
- 理解循环神经网络(RNN)的基本原理:通过构建一个基于RNN的诗歌生成模型,学会RNN是如何处理序列数据的,以及如何在PyTorch中实现它。
- 掌握文本数据的预处理技巧,并学会构建一个文本生成模型
- 加深对循环神经网络的了解
三、实验过程
1.搭建模型
整体思路:
先进行文本预处理,读取诗歌数据,清理文本数据,并构建词汇表,记录每个字符的出现频率。然后将清理过的文本数据转换成模型可用的数字表示形式,并将整数表示的文本数据切分为多个序列,构建训练数据集。随后,定义一个基于RNN的模型,通过训练数据集迭代训练模型来优化模型参数。模型训练完成后可利用模型生成一定长度的新诗歌文本。
1)导入库和检查GPU可用性
导入Pytorch库并检查GPU是否可用。如果GPU可用,返回"True"
导入进行数据预处理和标记所需的库
2)定义超参数
定义了学习率、最大训练轮次、批处理大小以及是否使用GPU的标志。
3)数据处理
引入诗歌文件,形成诗歌数据集,并通过替换换行符和中文标点符号来清理文本
'TextConverter'类负责对文本数据进行预处理和转换
字符到整数和整数到字符的转换方法:
- word_to_int方法接受一个字符作为参数,返回字符在词汇表中的整数索引。如果字符不在词汇表中,则返回词汇表大小。
- int_to_word方法接受一个整数索引作为参数,返回该索引对应的字符。如果索引等于词汇表大小,返回中文逗号",";如果索引小于词汇表大小,则返回对应的字符;否则,抛出异常。
文本到数组和数组到文本的转换方法:
- text_to_arr方法接受一个文本字符串作为参数,返回一个由文本中每个字符对应整数索引组成的NumPy数组。
- arr_to_text方法接受一个整数索引数组作为参数,返回由数组中每个索引对应字符组成的字符串
准备数据集
定义数据集
4)定义RNN模型
使用PyTorch的nn.Module定义了RNN模型的结构
通过嵌入层将字符索引映射为密集向量,然后通过RNN层处理这些向量序列。最后,通过线性层将RNN输出映射为词汇表大小的向量。
5)模型初始化、损失和优化器
使用交叉熵损失函数(nn.CrossEntropyLoss())来度量模型输出与实际标签之间的差异。
使用Adam优化器(torch.optim.Adam)来更新模型参数,其中学习率为Learning_rate。
6)训练循环
通过反复迭代,模型在每个Epoch中根据训练数据调整参数,逐渐提高对中文诗歌模式的学习,使得生成的文本更符合训练数据的特征
2.对模型进行优化、改进
1)运行程序
根据提供的训练输出结果来看,Perplexity的数值较大,而Loss较高,说明模型在训练数据上的拟合效果相对较差。通常情况下,Perplexity较低且Loss较小的模型效果更好。
分析可能导致模型效果一般的原因:
- 增加模型复杂性:添加更多层或增加现有层中的隐藏单元数
- 使用LSTM或者GRU:捕捉序列中的长期依赖关系
- 调整嵌入维度:尝试不同的myRNN类中的embed_dim参数值
- 调整学习率
- 增加训练次数
- 实现验证集:将数据集拆分为训练集和验证集。使用验证集来监控训练过程中模型的性能。在验证损失不再下降或开始上升时停止训练。
2)修改模型结构,使用LSTM结构
并且将训练次数增加到50
输出结果为:
调整学习率为1e-5 ,输出
3)实现测试集:将数据集拆分为训练集和测试集
发现多次调参,调整Embedding层,调模型结构都没调出合适的模型,输出的诗句有很多重复的字。
4)选择将原模型增加测试集进行尝试
输出结果为
考虑到古诗上下文之间有一定的关联性
将n_step设置为30
输出结果为
将n_step设置为40
输出结果为
发现这种情况是所有实验中Loss最小的一种
四、实验结果
经过多次调参,优化模型,发现使用RNN结构,学习率为1e-4,epochs为50,n_setp为40时,得出的Loss最小。
五、实验总结
在修改深度学习代码,特别是从RNN迁移到LSTM的过程中,我遇到了一些挑战。首先,了解LSTM与RNN的区别和工作原理对于成功修改代码至关重要。其次,我注意到LSTM层的输入格式要求与RNN不同,需要将batch_first设置为True。在调试过程中,还遇到了一些GPU不可用的问题,通过检查CUDA是否可用、GPU驱动程序和PyTorch版本等方面找到解决方案。总的来说,通过修改代码将RNN替换为LSTM,我更深入地理解了这两者之间的差异。但是,由于自己的能力有限,在修改为LSTM后并没有成功优化模型。所以,最后还是将RNN结构模型增加测试集,得出一个相对较好的结果。