前言
大家好,我是阿光。
本专栏整理了《PyTorch深度学习项目实战100例》,内包含了各种不同的深度学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集。
正在更新中~ ✨
🚨 我的项目环境:
- 平台:Windows10
- 语言环境:python3.7
- 编译器:PyCharm
- PyTorch版本:1.8.1
💥 项目专栏:【PyTorch深度学习项目实战100例】
一、LSTM自动AI作诗
本项目使用了LSTM作为模型实现AI作诗,作诗模式分为两种,一是根据给定诗句继续生成完整诗句,二是给定诗头生成藏头诗。
在这里插入图片描述
二、数据集介绍
数据来源于chinese-poetry,最全中文诗歌古典文集数据库
最全的中华古典文集数据库,包含 5.5 万首唐诗、26 万首宋诗、2.1 万首宋词和其他古典文集。诗 人包括唐宋两朝近 1.4 万古诗人,和两宋时期 1.5 千古词人。
实验使用预处理过的二进制文件 tang.npz 作为数据集,含有 57580 首唐诗,每首诗限定在 125 词, 不足 125 词的以空格填充。数据集以 npz 文件形式保存,包含三个部分:
data: (57580,125) 的 numpy 数组,总共有 57580 首诗歌,每首诗歌长度为 125 字符 (不足 125 补空格,超过 125 的丢弃),将诗词中的字转化为其在字典中的序号表示
ix2word: 序号到字的映射word2ix: 字到序号的映射
三、算法流程介绍
1.输入数据为input,形状为 124 * 16 2.输入数据的label为 124 * 16 3. 之后需要对输入数据进行嵌入,如果不嵌入那么每个古诗的字应为对应的索引,为了能够进行训练所以需要将其进行嵌入,然后形成连续性变量。 4. 之后我们的数据就变成了 124 * 16 * embedding_dim 5. 然后将其导入到LSTM模块中,则形成的形状为 124 * 16 * hidden_dim 6. 之后将其导入到全连接层,形成分类,变为的形状为 124 * 16 ,vocab_size
「注意」 一定要清楚各个位置不同变量的形状,这些在代码中已经注明,一定要弄明白batch_size,time_step,embedding_dim,vocal_size,num_layers,hidden_dim以及input_size在代码中的意义。
四、定义网络模型
项目中使用的模型是LSTM,在模型中我们定义了三个组件,分别是embedding层,lstm层和全连接层。
- Embedding层:将每个词生成对应的
嵌入向量,就是利用一个连续型向量来表示每个词 - Lstm层:提取诗句中的语义信息
- Linear层:将结果映射成
vocab_size大小用于分类,即每个字的概率
class LSTM(nn.Module):
def __init__(self, vocab_size, embedding_dim, hidden_dim):
super(LSTM, self).__init__()
self.hidden_dim = hidden_dim
self.embeddings = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers)
self.linear = nn.Linear(hidden_dim, vocab_size)
def forward(self, x, hidden=None):
time_step, batch_size = x.size() # 124, 16
if hidden is None:
h_0 = x.data.new(num_layers, batch_size, self.hidden_dim).fill_(0).float()
c_0 = x.data.new(num_layers, batch_size, self.hidden_dim).fill_(0).float()
else:
h_0, c_0 = hidden
embeds = self.embeddings(x)
output, (h_n, c_n) = self.lstm(embeds, (h_0, c_0))
output = self.linear(output.reshape(time_step * batch_size, -1))
return output, (h_n, c_n)
五、给定首句生成古诗
该函数会根据给定的语句生成一段古诗,会根据start_words继续生成下一个字,对于给定的语句生成相应的hidden,然后将最后一个字和对应的hidden将其输入到模型中,生成新的下一个字,然后将新生成的字作为新的输入。
此外还可以加入诗句前缀,加入的目的是会影响生成诗句的风格,首先利用prefix_words生成对应的hidden,然后将hidden送入模型生成诗句,此hidden中包含了前缀中的语义信息。
- start_words:给定的初始语句,基于它生成之后的诗句
- prefix_words:前缀诗句,该句会影响诗句的风格,因为首先会学习对应的hidden然后将其和开始词送入模型生成对应的诗句
# 给定首句生成诗歌
def generate(model, start_words, ix2word, word2ix, prefix_words=None):
results = list(start_words) # 开始词的列表 ["床", "前", "明", "月", "光"]
start_words_len = len(start_words) # 开始词的长度
# 第一个词语是<START>
input = torch.Tensor([word2ix['<START>']]).view(1, 1).long() # "<START>"对应的索引8094
if use_gpu:
input = input.cuda()
hidden = None
# 若有风格前缀,则先用风格前缀生成hidden
# 第一个"<START>"作为默认输入,然后遍历前缀词列表(不同于开始词),一个词一个词作为输入,生成hidden
# 这种方式形成的hidden就是根据床前明月光形成的hidden,这样形成的hidden中就包含了床前明月光的语义信息
# 这样就可以根据这个前缀学习出风格
if prefix_words:
# 第一个input是<START>,后面就是prefix中的汉字
# 第一个hidden是None,后面就是前面生成的hidden
for word in prefix_words:
output, hidden = model(input, hidden)
input = input.data.new([word2ix[word]]).view(1, 1)
# 开始真正生成诗句,如果没有使用风格前缀,则hidden = None,input = <START>
# 否则,input就是风格前缀的最后一个词语,hidden也是生成出来的
for i in range(max_gen_len):
output, hidden = model(input, hidden)
# print(output.shape)
# 如果还是开始诗句,输入就是开始词中的字,不取出结果,只为了得到最后的hidden
if i < start_words_len:
w = results[i]
input = input.data.new([word2ix[w]]).view(1, 1)
# 否则将output作为下一个input进行
else:
# print(output.data[0].topk(1))
# top_index = output.data[0].topk(1)[1][0].item()
top_index = output.argmax().item() # 最后生成的词的下标,output为8293维度,获取概率最大的索引
w = ix2word[top_index] # 根据该下标获得对应的字
results.append(w) # 将生成的词加入结果诗句中
input = input.data.new([top_index]).view(1, 1)
# 如果生成的词为结束词"<EOP>",则结束生成诗句,并将"<EOP>"从结果列表中删除
if w == '<EOP>':
del results[-1]
break
return results
六、生成藏头诗
生成藏头诗的原理与上述函数同理,只不过是利用给定的藏头字分别作为输入,一旦遇到特殊符号就说明该句生成结束,继续生成下一句藏头诗
同理这个函数也会包含诗句前缀,影响诗句的风格
七、模型训练
对于模型训练最重要的就是模型的输入和输出,针对于写诗这个任务,我们的输入应该是给定一句诗,然后错位1位作为它的标签用于监督,例如:
床前明月光疑是地上霜 那么我们的输入、输出就应该为: 输入数据:床前明月光疑是地上 输出数据:前明月光疑是地上霜
每个时间步对应的输出应该是他下个时间步对应的字 每个时间步的输出应该是vocab_size维度,就是词大小,用于全分类,这样就会根据概率获得该时间步对应的字。
由于本项目中采用的是唐诗数据集,数据为data: (57580,125) 的 numpy 数组,也就是每个样本为一句诗,每首诗中含有125个字,相当于不同的时间步,然后将每个字进行embedding进行编码,这里我们将输入作为124,也就是像上面所说,利用前124个字和他对应之后的124个字进行监督。
八、生成诗句
该函数用于进行测试生成语句,我们会首先加载我们训练好的模型,然后传入续写的诗句或者需要加入的前缀信息,形成诗句。
完整源码
【PyTorch深度学习项目实战100例】—— 使用pytorch实现LSTM自动AI作诗(藏头诗和首句续写)| 第6例_咕 嘟的博客-CSDN博客_pytorch基于 lstm 的自动写诗