使用深度学习模型创作动漫故事,比较LSTM和GPT2的文本生成方法(上)

本文涉及的产品
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
交互式建模 PAI-DSW,5000CU*H 3个月
模型训练 PAI-DLC,5000CU*H 3个月
简介: 使用深度学习模型创作动漫故事,比较LSTM和GPT2的文本生成方法

这个项目的动机是想看看在短短的几年时间里NLP领域的技术已经走了多远,特别是当它涉及到生成创造性内容的时候。通过生成动画概要,我探索了两种文本生成技术,首先是使用相对陈旧的LSTM,然后使用经过微调的GPT2。

640.png

在这篇文章中,您将看到AI创建这种废话开始的过程。。。

A young woman capable : a neuroi laborer of the human , where one are  sent back home ? after defeating everything being their resolve the  school who knows if all them make about their abilities . however of  those called her past student tar barges together when their mysterious  high artist are taken up as planned while to eat to fight !

这件艺术

A young woman named Haruka is a high school student who has a crush on a mysterious girl named Miki. She is the only one who can remember the  name of the girl, and she is determined to find out who she really is.

为了能够了解本篇文章,你必须具备以下知识:

  • Python编程
  • Pytorch
  • RNNs的工作原理
  • Transformers

好吧,让我们看一些代码!

数据描述

这里使用的数据是从myanimelist中抓取的,它最初包含超过16000个数据点,这是一个非常混乱的数据集。所以我采取以下步骤清理:

删除了所有奇怪的动漫类型(如果你是一个动漫迷,你就会知道我在说什么)。

每个大纲在描述的最后都包含了它的来源(例如:source: myanimelist, source: crunchyroll等),所以我也删除了它。

基于电子游戏、衍生品或改编的动画都有非常少的概要总结,所以我删除了所有少于30的概要,我也删除了所有包含“衍生品”、“基于”、“音乐视频”、“改编”的概要。这样处理的逻辑是,这些类型的动画不会真正让我们的模型有创意。

我还删除了大纲字数超过300的动画。这只是为了使培训更容易(请查看GPT2部分以了解更多细节)。

删除符号。

一些描述也包含日文,所以这些也被删除了。

LSTM方式

传统的文本生成方法使用循环的LSTM单元。LSTM(长短期记忆)是专门设计来捕获顺序数据中的长期依赖关系的,这是常规的RNNs所不能做到的,它通过使用多个门来控制从一个时间步骤传递到另一个时间步骤的信息。

直观地说,在一个时间步长,到达LSTM单元的信息经过这些门,它们决定是否需要更新信息,如果它们被更新,那么旧的信息就会被忘记,然后新的更新的值被发送到下一个时间步长。要更详细地了解LSTMs,可以浏览我们发布的一些文章。

创建数据集

因此,在我们构建模型架构之前,我们必须标记概要并以模型接受的方式处理它们。

在文本生成中,输入和输出是相同的,只是输出标记向右移动了一步。这基本上意味着模型接受输入的过去的单词并预测下一个单词。输入和输出令牌分批传递到模型中,每个批处理都有固定的序列长度。我已经按照这些步骤来创建数据集:

  • 创建一个配置类。
  • 将所有的概要合并在一起。
  • 标记对照表。
  • 定义批数。
  • 创建词汇,单词索引和索引到单词字典。
  • 通过向右移动输入标记来创建输出标记。
  • 创建一个生成器函数,它批量地输出输入和输出序列。

# code courtesy: https://machinetalk.org/2019/02/08/text-generation-with-pytorch/


classconfig:    
#storestherequiredhyerparametersandthetokenizerforeasyaccesstokenizer=nltk.word_tokenizebatch_size=32seq_len=30emb_dim=100epochs=15hidden_dim=512model_path='lm_lrdecay_drop.bin'defcreate_dataset(synopsis,batch_size,seq_len):
np.random.seed(0)
synopsis=synopsis.apply(lambdax: str(x).lower()).valuessynopsis_text=' '.join(synopsis)
tokens=config.tokenizer(synopsis_text)
globalnum_batchesnum_batches=int(len(tokens)/(seq_len*batch_size))
tokens=tokens[:num_batches*batch_size*seq_len]
words=sorted(set(tokens))        
w2i= {w:ifori,winenumerate(words)}
i2w= {i:wfori,winenumerate(words)}
tokens= [w2i[tok] fortokintokens]
target=np.zeros_like((tokens))
target[:-1] =tokens[1:]
target[-1] =tokens[0]
input_tok=np.reshape(tokens,(batch_size,-1))
target_tok=np.reshape(target,(batch_size,-1))
print(input_tok.shape)
print(target_tok.shape)
vocab_size=len(i2w)
returninput_tok,target_tok,vocab_size,w2i,i2wdefcreate_batches(input_tok,target_tok,batch_size,seq_len):
num_batches=np.prod(input_tok.shape)//(batch_size*seq_len)foriinrange(0,num_batches*seq_len,seq_len):
yieldinput_tok[:,i:i+seq_len], target_tok[:,i:i+seq_len]

模型架构

我们的模型由一个嵌入层、一堆LSTM层(我在这里使用了3个层)、dropout层和最后一个输出每个词汇表标记的分数的线性层组成。我们还没有使用softmax层,你很快就会明白为什么。

因为LSTM单元也输出隐藏状态,所以模型也返回这些隐藏状态,以便在下一个时间步骤(下一批单词序列)中将它们传递给模型。此外,在每个epoch之后,我们需要将隐藏状态重置为0,因为在当前epoch的第一个time step中,我们不需要来自前一个epoch的最后一个time step的信息,所以我们也有一个“zero_state”函数。

classLSTMModel(nn.Module):    
def__init__(self,hid_dim,emb_dim,vocab_size,num_layers=1):
super(LSTMModel,self).__init__()
self.hid_dim=hid_dimself.emb_dim=emb_dimself.num_layers=num_layersself.vocab_size=vocab_size+1self.embedding=nn.Embedding(self.vocab_size,self.emb_dim)
self.lstm=nn.LSTM(self.emb_dim,self.hid_dim,batch_first=True,num_layers=self.num_layers)
self.drop=nn.Dropout(0.3)
self.linear=nn.Linear(self.hid_dim,vocab_size) #fromherewewillrandomlysampleaworddefforward(self,x,prev_hid):
x=self.embedding(x)
x,hid=self.lstm(x,prev_hid)
x=self.drop(x)
x=self.linear(x)
returnx,hiddefzero_state(self,batch_size):
return (torch.zeros(self.num_layers,batch_size,self.hid_dim),torch.zeros(self.num_layers,batch_size,self.hid_dim))

训练

然后我们只需要定义训练函数,存储每个epoch的损失,并保存损失最大的模型。我们还在每个epoch之前调用零状态函数来重置隐藏状态。

我们使用的损失函数是交叉熵损失,这就是为什么我们没有通过显式softmax层的输出,因为这个损失函数计算内部。

所有的训练都是在GPU上完成的,下面是正在使用的参数(在config类中提供):

  • 批次大小 = 32
  • 最大序列长度 = 30
  • 词嵌入维度 = 100
  • 隐藏层尺寸 = 512
  • 训练轮次 = 15
defloss_fn(predicted,target):
loss=nn.CrossEntropyLoss()
returnloss(predicted,target)
#====================================================================================================================================deftrain_fn(model,device,dataloader,optimizer):
model.train()
tk0=tqdm(dataloader,position=0,leave=True,total=num_batches)
train_loss=AverageMeter()  
hid_state,cell_state=model.zero_state(config.batch_size)
hid_state=hid_state.to(device)
cell_state=cell_state.to(device)
losses= []
forinp,targetintk0:
inp=torch.tensor(inp,dtype=torch.long).to(device)
target=torch.tensor(target,dtype=torch.long).to(device)
optimizer.zero_grad()        
pred,(hid_state,cell_state) =model(inp,(hid_state,cell_state))
#print(pred.transpose(1,2).shape)
loss=loss_fn(pred.transpose(1,2),target)
hid_state=hid_state.detach()
cell_state=cell_state.detach()
loss.backward()
_=torch.nn.utils.clip_grad_norm_(model.parameters(),max_norm=2) #toavoidgradientexplosionoptimizer.step()
train_loss.update(loss.detach().item())
tk0.set_postfix(loss=train_loss.avg)
losses.append(loss.detach().item())
returnnp.mean(losses)
#====================================================================================================================================defrun():
device='cuda'model=LSTMModel(vocab_size=vocab_size,emb_dim=config.emb_dim,hid_dim=config.hidden_dim,num_layers=3).to(device)
optimizer=torch.optim.Adam(model.parameters(),lr=0.001)
scheduler=torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer=optimizer, mode='min', patience=2, verbose=True, factor=0.5)
epochs=config.epochsbest_loss=999foriinrange(1,epochs+1):
train_dataloader=create_batches(batch_size=config.batch_size,input_tok=input_tok,seq_len=config.seq_len,target_tok=target_tok)
print('Epoch..',i)
loss=train_fn(model,device,train_dataloader,optimizer)
ifloss<best_loss:
best_loss=losstorch.save(model.state_dict(),config.model_path)
scheduler.step(loss)
torch.cuda.empty_cache()
returnmodel

生成动漫文本

在文本生成步骤中,我们向模型提供一些输入文本,例如,' A young woman ',我们的函数将首先对其进行标记,然后将其传递到模型中。该函数还取我们想要输出的概要的长度。

模型将输出每个词汇表标记的分数。然后我们将对这些分数应用softmax将它们转换成概率分布。

然后我们使用top-k抽样,即从n个词汇表中选择概率最高的k个标记,然后随机抽样一个标记作为输出返回。

然后,该输出被连接到输出的初始输入字符串中。这个输出标记将成为下一个时间步骤的输入。假设输出是“capable”,然后我们连接的文本是“A young woman capable”。我们一直这样做,直到输出最后的结束标记,然后打印输出。

这里有一个很好的图表来理解模型在做什么

640.png

definference(model,input_text,device,top_k=5,length=100):
output=''model.eval()
tokens=config.tokenizer(input_text)
h,c=model.zero_state(1)
h=h.to(device)
c=c.to(device)
fortintokens:
output=output+t+' 'pred,(h,c) =model(torch.tensor(w2i[t.lower()]).view(1,-1).to(device),(h,c))
#print(pred.shape)
foriinrange(length):
_,top_ix=torch.topk(pred[0],k=top_k)
choices=top_ix[0].tolist()                
choice=np.random.choice(choices)
out=i2w[choice]
output=output+out+' 'pred,(h,c) =model(torch.tensor(choice,dtype=torch.long).view(1,-1).to(device),(h,c))
returnoutput#============================================================================================================device='cpu'mod=LSTMModel(emb_dim=config.emb_dim,hid_dim=config.hidden_dim,vocab_size=vocab_size,num_layers=3).to(device)
mod.load_state_dict(torch.load(config.model_path))
print('AI generated Anime synopsis:')
inference(model=mod, input_text='In the ', top_k=30, length=100, device=device)
目录
相关文章
|
1月前
|
机器学习/深度学习 数据可视化 网络架构
增强深度学习模型的可解释性和泛化能力的方法研究
【8月更文第15天】在深度学习领域,模型的准确率和预测能力是衡量模型好坏的重要指标。然而,随着模型复杂度的增加,它们往往变得越来越难以理解,这限制了模型在某些关键领域的应用,例如医疗诊断、金融风险评估等。本文将探讨如何通过几种方法来增强深度学习模型的可解释性,同时保持或提高模型的泛化能力。
90 2
|
1月前
|
人工智能 自然语言处理
公理训练让LLM学会因果推理:6700万参数模型比肩万亿参数级GPT-4
【8月更文挑战第3天】新论文提出“公理训练”法,使仅有6700万参数的语言模型掌握因果推理,性能媲美万亿级GPT-4。研究通过大量合成数据示例教授模型因果公理,实现有效推理并泛化至复杂图结构。尽管面临合成数据需求大及复杂关系处理限制,此法仍为语言模型的因果理解开辟新途径。[链接: https://arxiv.org/pdf/2407.07612]
41 1
|
25天前
|
知识图谱
ARTIST的中文文图生成模型问题之通过GPT生成图像序列的问题如何解决
ARTIST的中文文图生成模型问题之通过GPT生成图像序列的问题如何解决
|
27天前
|
机器学习/深度学习 API 异构计算
7.1.3.2、使用飞桨实现基于LSTM的情感分析模型的网络定义
该文章详细介绍了如何使用飞桨框架实现基于LSTM的情感分析模型,包括网络定义、模型训练、评估和预测的完整流程,并提供了相应的代码实现。
|
27天前
|
机器学习/深度学习 自然语言处理 算法
7.1.3、使用飞桨实现基于LSTM的情感分析模型
该文章介绍了如何使用飞桨(PaddlePaddle)实现基于长短时记忆网络(LSTM)的情感分析模型,包括数据处理、网络定义、模型训练、评估和预测的详细步骤。
|
9天前
|
数据可视化 Swift
小钢炮进化,MiniCPM 3.0 开源!4B参数超GPT3.5性能,无限长文本,超强RAG三件套!模型推理、微调实战来啦!
旗舰端侧模型面壁「小钢炮」系列进化为全新 MiniCPM 3.0 基座模型,再次以小博大,以 4B 参数,带来超越 GPT-3.5 的性能。并且,量化后仅 2GB 内存,端侧友好。
小钢炮进化,MiniCPM 3.0 开源!4B参数超GPT3.5性能,无限长文本,超强RAG三件套!模型推理、微调实战来啦!
|
1月前
长上下文能力只是吹牛?最强GPT-4o正确率仅55.8%,开源模型不如瞎蒙
【8月更文挑战第10天】新研究NoCha挑战显示,即使是顶级的大型语言模型GPT-4o,在处理长篇幅文本时正确率仅55.8%,低于人类直观水平。该挑战基于近作英文小说,检验模型对整本书信息的理解与推理能力。结果显示,模型在全局推理上的表现不佳,倾向于依赖局部信息而非整体上下文,尤其是在复杂推理需求高的科幻小说上表现更弱。这一发现揭示了当前模型在处理长上下文任务上的局限性。论文链接: [https://arxiv.org/pdf/2406.16264](https://arxiv.org/pdf/2406.16264)。
116 65
|
1月前
|
人工智能
ECCV 2024:让GPT-4图像理解更易出错,全新策略增强VLP模型对抗迁移性
【8月更文挑战第13天】在AI领域,视觉语言预训练(VLP)模型展现出了强大的图像与文本理解能力,但也易受多模态对抗样本攻击。为此,研究者提出了Cross-Clean-Adversarial Regional Diversification (CCAR-Div)策略,通过增强对抗样本多样性以提升VLP模型的对抗迁移性。此策略在对抗轨迹交集区域采样,增加样本多样性,并利用模态交互作用。经Flickr30K和MSCOCO数据集验证,CCAR-Div能有效提高跨模型与跨任务场景下的对抗迁移性,如使用ALBEF生成的对抗样本攻击TCL时,成功率高达95.58%。
110 60
|
8天前
|
人工智能 自然语言处理 数据挖掘
【通义】AI视界|性能超越GPT-4o?最强大的开源AI模型来了……
本文介绍了五项最新AI技术动态,包括性能超越GPT-4o的开源AI模型Reflection70B、智谱清言App限时免费的视频通话功能、哈佛医学院研发的癌症诊断AI模型CHIEF、Replit推出的AI编程助手,以及英特尔与日本AIST合作设立的芯片制造研发中心。这些进展展示了AI领域的快速创新与广泛应用。更多详情,请访问通义官网体验。
|
10天前
|
机器学习/深度学习
数百万晶体数据训练、解决晶体学相位问题,深度学习方法PhAI登Science
【9月更文挑战第5天】近期,《科学》杂志报道了一项名为PhAI的深度学习技术,在晶体学相位问题上取得重要突破。相位问题旨在确定晶体中分子或原子的位置与方向,对理解其物理化学特性至关重要。PhAI通过数百万晶体数据训练,能高效准确地解决这一难题,有望大幅提升研究效率,加速新材料和药物的设计。但其准确性及对未知结构处理能力仍面临挑战。论文详情参见:https://www.science.org/doi/10.1126/science.adn2777。
16 1