『NLG学习』(二)教你搭建自己的Transformer
更新时间:2026-02-15 12:02:11
-
-
爱情和生活模拟rpg手机版
- 类型:体育竞技
- 大小:87.5mb
- 语言:简体中文
- 评分:
- 查看详情
『NLG学习』(二)教你搭建自己的Transformer
本文聚焦于Transformer的介绍和应用,突显了其相对于CNN与RNN的优势,包括并行计算、自注意力机制等关键特性。接着,详细解释了构建Transformer所需的五个基本零件及其算法实现,如嵌入、位置编码、掩码等,并提供了数据预处理、各组件实现及组装训练的代码示例,展示了结果并指出了不足之处,特别是位置编码处理存在一些问题。
Abstract(摘要)
在过去的模型中,主要的序列转导方法通常依赖于复杂的递归或卷积神经网络(CNN),包括编码器和解码器的组合。经过改进,性能最佳的模型则通过注意力机制连接这两个部分。然而,好景不长,谷歌的顶尖专家们提出了transformer,这个创新性模型极大地促进了并行计算能力,提高了训练与推理的速度,并且加入了自注意力机制以更好地处理序列时间维度上的关系。相较于传统的模型,transformer 兼备了 CNN 与 RNN 的优点:它实现了参数局部共享,从而减少了参数量(CNN 最大的特点),同时还能关注任意两个单词之间的依赖关系。这种能力彻底解决了RNN 对于长期依赖关系的无力感,使得文本处理任务变得异常高效且准确。尽管谷歌大佬们的这篇“attention is all you need”在学术上非常引人注目,但由于其晦涩难懂,导致了许多研究人员和学者难以完全理解。然而,在笔者查阅了大量资料后,才开始对transformer有了一定的了解。接下来,让我们一起揭开transformer的秘密吧!
Introduction(介绍)
Transformers摒弃了传统CNN和RNN架构的限制,仅依赖全连接层与自注意力机制进行处理,因此训练速度显著加快。在encoder部分采用并行计算技术,相比使用RNN,速度大幅提升。要构建自己的Transformer模型,需五个关键组件:词嵌入(Embedding the inputs)、位置编码(Positional Encodings)、创建掩码(Creating Masks)、多头注意力层(The Multi-Head Attention layer)和前馈神经网络(The Feed-Forward layer)。这些元素共同构成了高效的自然语言处理工具。
下面让我们一步步地开始学习吧
Algorithm(算法)
1)Embedding
如今,采用嵌入方法已是广泛接受的做法之一。相较于one-hot编码方法,嵌入能够承载的信息量显著增强,实作起来也更为简单,直接调用API即可完成。当输入每个单词时,该代码将执行查找和检索其嵌入向量的过程。随后,这些向量将成为模型学习参数的重要依据,并在每次迭代过程中随着梯度下降进行调整。
2)position-encoding
刚才的embedding是为了让机器理解单词的意思,这是为了使机器能够理解和排列每个单词的重要性。然而,实际上这篇论文并未很好地处理这一部分。尽管如此,它采用了三角函数进行映射,这是一个权宜之策。接下来,请看作者是如何处理这一问题的。

这是该trick的示意图,行为pos,列为i

这是本文的关键词位置编码,乍一看似乎有些怪异,但实际上效果不错。以下为大佬绘制的示意图,展示了其对这一编码方式的困惑之处。详细实现方法可参见下面的Implement部分。

算出位置编码之后,我们就可以将位置编码与变换后的嵌入向量相加。
为什么将嵌入向量进行变换?在学习到这里,为什么要对嵌入向量进行变换?有大神认为这是一个经验之谈。简单来说,原本嵌入向量值偏小,而位置编码的范围是[- ,如果带入d_k的值,除以根号d_k后,位置编码的范围可以缩小为[- 。这使得相加后的结果更加平滑和可控,从而减轻嵌入向量对最终分类任务的影响。希望你们喜欢这种做法!
3)create our mask
在自然语言处理(NLP)领域中,“掩码”机制是理解和生成任务中不可或缺的一部分。特别是在训练深度学习模型时,使用这种掩码技术可以帮助防止数据泄漏和提高模型的性能。掩码的概念 首先,我们需要了解“掩码”是什么。它是一种特殊的矩阵操作,用于在机器翻译、序列到序列学习(Seqeq)等场景中防止信息泄露。简而言之,掩码的作用是暂时屏蔽某些输入或输出部分的信息,以保持模型的训练数据的有效性。掩码的重要性 在编码器-解码器架构中,我们通常需要对填充字符进行遮掩处理,这是因为在序列标注任务中,这些填充字符实际上并不包含任何有效信息。通过使用掩码,我们可以确保模型不会依赖于这些无效的信息,并且有助于更有效地学习和表示输入数据。掩码的实施 在训练过程中,我们会看到矩阵的一致性要求以及对pad(填充)元素的遮掩处理。这种操作可以通过添加padding来进行实现,即在每一行中使用掩码来抑制未使用的填充字符,以保持矩阵的一致性。此外,在解码部分,我们还需要遮掩掉预测结果之外的部分,比如在机器翻译任务中,我们将遮掩住之后出现的单词,防止模型学习“跳过”或跳跃式地生成。下三角矩阵的应用 为了进一步增强模型的有效训练和泛化能力,我们采用了下三角矩阵来操作。这种矩阵的行和列都对应着句子长度(sen_len),这与填充元素的处理类似。通过这种方式,我们可以更有效地训练模型,使其在解码过程中避免对未生成部分的关注。总结 掩码技术的核心是防止信息泄露、保持数据的有效性和提高模型的训练效果。通过对填充元素和预测结果的遮掩,我们能够帮助机器学习到更有意义的信息,并最终产生更好的翻译或文本生成结果。通过这样的方法,我们可以更有效地训练深度学习模型,从而提升其性能在自然语言处理任务中的表现。
下面是掩码的一个栗子
4)MutiHeadAttention
在本项目的核心部分,我们将探讨到一个重要机制自注意力(Self-Attention)。要理解这一概念,我们需要从一个基础的模型开始,那就是Scaled Dot-Product Attention。首先,让我们从“注意力”这个核心概念入手。一般来说,机器会关注源序列(Source Sequence)中与目标序列(Target Sequence)之间的相关部分,这可以帮助翻译任务更好地进行。在经典文本翻译的例子中:- 源语言:“我是中国人” - 目标语言:“I am Chinese”这种情况下,注意力机制会特别强调“我是”和“I”的关系,“中国”和“Chinese”的关系。然而,在自注意力机制(Self-Attention)的情况下,机器不再只关注源序列中的所有词对,而是专门针对目标序列进行注意力分配。具体来说:- 源语言:“我是中国人” - 目标语言:“I am Chinese”在这个例子中,“我”与“I”的关系仍然被重点关注,而“中国”与“Chinese”的关系也得到了同等的注意。通过这种方式,自注意力机制能更精细地处理和分析源序列中的信息,从而更好地理解并生成目标语言。这在自然语言处理任务中是一项非常重要的技术突破。
好,了解了自注意力的通俗含义,我们再来理解自注意力的计算过程。

首先,我们将嵌入向量与三个矩阵进行点乘,得到query、key和value三个新向量。这里query是待匹配的向量,key是被匹配的向量,然后将query与key进行点乘,得到它们的匹配程度,这是pad这个token的地方进行了遮掩处理,根据我们先前得到的掩码,之后使用softmax进行大小的缩放,最后将结果与value进行点乘,即机器到底要注意哪些内容。这里的所有操作都是矩阵的点乘运算,实际上是解决了RNN的一大瓶颈。qkkk..进行相乘,在将qkkk..进行相乘,这个操作的意义非常伟大,它代表每两个单词之间都会计算它们之间的关系,即使距离再遥远,它们的相对距离也只是n(,堪称触手可及。
这是query,key,value向量计算的示意图

在深入探讨自注意力机制后,我们将关注其进阶版本多头注意力机制。在此设计中,我们首先对q、k、v三个向量进行细致切分,将其分为heads(多个)部分。每个部分都将被独立地应用我们的传统注意力计算方法,这不仅实现了更丰富的信息处理能力,还显著增强了模型的深度理解和复杂推理能力。最后,我们将这些处理后的结果合并起来,共同构建出最终的输出。

这是整个多头注意力的流程示意图

看完这个,恭喜你完成了所有零件的介绍,最后一步即将揭晓。准备好了吗?开始吧!
5)FeedForward
这个组件十分简单,其流程为:首先,输入数据经由全连接层处理;然后,应用ReLU激活函数;最后,再次通过全连接层完成。
组装
零件制作完了,下面就是组装了,具体大家可以看下面的实现 EncoderLayer与DecoderLayer Encoder与Decoder Transformer
transformer的整体架构
Implement(实作)
数据预处理
In [1]
import numpy as npimport re#将无效字符去掉with open("data/data86810/human_chat.txt","r",encoding="utf-8") as f: data=f.read().replace("Human 1"," ").replace("Human 2"," ").replace("."," ").replace("*"," ").replace("@"," ").replace("^"," ").replace("&"," ").replace("!"," ").replace("#"," ").replace("$"," ").replace("?"," ").replace(";"," ").replace(":"," ").replace(","," ").replace('"',' ').replace("%"," ").replace("/"," ").replace("@"," ").replace("("," ").replace(")"," ").replace("'"," ").lower() data=list(data.split("\n"))#print(len(data))lst=[]#分割出单词,连成序列for obj in data: sen=list(obj.split(" ")) lst.append(sen)#print(len(lst))#将字符连接起来,制作字典string=" ".join(data)#将特殊字符添入string1="pad sos eos"#合并字符串string=string+string1#string=string.replace(''," ")#使用正则分割,防止有多个空格words=re.split(" +",string)#使用集合,防止单词重复words=list(set(words))print(len(words))#获取字典dic=dict([(word,i) for i,word in enumerate(words)])#存储对话序列index_data=[]#每句话的长度,短句添加"pad",长句切至30sen_len=30for i,sen in enumerate(lst): #token映射至index,并防止出现空字符 sen=[dic[word] for word in sen if word!=''] #在开头添加"sos" sen.insert(0,dic["sos"]) while len(sen)<sen_len-1: #填充"pad",防止长度不够 sen.append(dic["pad"]) #切取sen_len-1个词 sen=sen[:sen_len-1] #末尾添加"eos" sen.append(dic["eos"]) #将ask与answer分割 if i%2==0: one=[] one.append(sen) else: one.append(sen) index_data.append(one)#print(len(index_data))index_data=np.array(index_data)print(index_data.shape)print(index_data[0])#挑一个看看效果ask,ans=index_data[3]#将index序列转化为字符串ask_str=[words[i] for i in ask] ans_str=[words[i] for i in ans]print(ask_str)print(ans_str)#print(dic)登录后复制
定义超参
In [2]
#单词嵌入的维度d_model=512#多头自注意力的个数heads=8#batch大小batch_size=128#encoder或decoder有多少层N=8#词典大小vocab_size=len(dic) dropout=0.1登录后复制
定义数据读取器
In [3]
import paddlefrom paddle.io import Dataset,DataLoaderimport paddle.nn as nnimport randomclass Mydataset(Dataset): def __init__(self,index_data,dic): super(Mydataset, self).__init__() self.index_data=index_data self.dic=dic def __getitem__(self,index): ask_data,ans_data=self.index_data[index] #ask部分倒序,引入更多短期依赖关系 ask_data,ans_data=ask_data[:][::-1],ans_data return ask_data,ans_data def __len__(self): return self.index_data.shape[0]#实例化读取器dataset=Mydataset(index_data,dic)#封装为迭代器dataloader=DataLoader(dataset,batch_size=batch_size,shuffle=True,drop_last=True)#看看效果ask,ans=next(dataloader())print(ask)登录后复制
Embedding
In [4]
import paddleimport paddle.nn as nn#定义嵌入层class Embedder(nn.Layer): def __init__(self,vocab_size,d_model): super(Embedder, self).__init__() self.emb=nn.Embedding(vocab_size,d_model) def forward(self,x): x=paddle.to_tensor(x,dtype="int64") return self.emb(x)登录后复制
PositionalEncoder
In [5]
import mathclass PositionalEncoder(nn.Layer): def __init__(self,d_model,max_seq_len=80): #d_model为嵌入维度 super(PositionalEncoder, self).__init__() self.d_model=d_model #保持位置编码与嵌入向量的形状可以相同 #嵌入向量[batch,sen_len,d_model] #位置编码[max_seq_len,d_model] #下面经过调整与广播使两者形状相同 position=paddle.zeros([max_seq_len,d_model]) #行为pos for pos in range(max_seq_len): #列为i for i in range(d_model,2): #公式 position[pos,i]=paddle.sin(pos/(10000**(2*i/d_model))) position[pos,i+1]=paddle.cos(pos/(10000**((2*i+1)/d_model))) self.position=position def forward(self,x): #对嵌入向量进行放缩,原因在前面的理论部分已讲 x=x*math.sqrt(self.d_model) seq_len=x.shape[1] #调整大小 x=x+self.position[:seq_len,:] return x x=paddle.randn([128,30,512])# model=PositionalEncoder(512)# print(model(x))登录后复制
Create mask
In [6]
```python def create_mask(src, trg): pad = dic[pad] # 获取对应布尔矩阵 src_mask = src != pad # True-> False->0 src_mask = paddle.cast(paddle.to_tensor(src_mask), dtype=int) trg_mask = trg != pad trg_mask = paddle.cast(paddle.to_tensor(trg_mask), dtype=int) # 初始化掩码矩阵(下三角) nopeak_mask = paddle.ones(trg.shape) for i in range(trg.shape[): for j in range(trg.shape[): if i >= j: nopeak_mask[i, j] = nopeak_mask = paddle.cast(paddle.to_tensor(nopeak_mask), dtype=int) # 将两个掩码矩阵相加 trg_mask += nopeak_mask return src_mask, trg_maskask_mask, ans_mask = create_mask(ask, ans) print(ans_mask) 登录后复制 ```
计算Attention
In [7]
import paddle.nn.functional as Fdef attention(q,k,v,d_k,mask=None,dropout=dropout): #q:query,k:key,v:value,d_k:d_model//heads #得到q与k的相似程度并做放缩 #print(q.shape,k.shape) similarity=paddle.matmul(q.transpose([0,3,1,2]),k.transpose([0,3,2,1]))/math.sqrt(d_k) similarity=similarity.transpose([0,2,3,1]) if mask is not None: #广播 mask=mask.unsqueeze(-1).unsqueeze(-1) #print(mask.shape) #print(similarity.shape) mask=paddle.broadcast_to(mask,similarity.shape) mask=paddle.cast(mask,dtype="int64") #得到布尔矩阵 zero_one=mask==0 #调整无需注意的地方为负无穷 similarity[zero_one.numpy()]=-1e9 #对矩阵值进行softmax,使sum为1 similarity=F.softmax(similarity) drop=nn.Dropout(dropout) similarity=drop(similarity) #求出对每个单词注意的程度 atten=paddle.matmul(similarity.transpose([0,3,1,2]),v.transpose([0,3,1,2])) return atten q=k=v=paddle.randn([batch_size,sen_len,8,64])print(attention(q,k,v,8,ask_mask).shape)登录后复制
MutiHeadAttention
In [8]
class MutiHeadAttention(nn.Layer): def __init__(self,d_model,heads,dropout=dropout): super(MutiHeadAttention, self).__init__() self.d_model=d_model self.h=heads self.d_k=d_model//heads #线性变换 self.q_linear=nn.Linear(d_model,d_model) self.k_linear=nn.Linear(d_model,d_model) self.v_linear=nn.Linear(d_model,d_model) self.dropout=dropout self.out=nn.Linear(d_model,d_model) def forward(self,q,k,v,mask): batch_size=q.shape[0] #求得query,key,value向量,并分组给各个头注意力 self.q=self.q_linear(q).reshape([batch_size,-1,self.h,self.d_k]) self.k=self.k_linear(k).reshape([batch_size,-1,self.h,self.d_k]) self.v=self.v_linear(v).reshape([batch_size,-1,self.h,self.d_k]) #获取注意的程度 atten=attention(self.q,self.k,self.v,self.d_k,mask,self.dropout) atten=atten.reshape([batch_size,-1,self.d_model]) out=self.out(atten) return out# model=MutiHeadAttention(512,8,0.1)# x=paddle.randn([batch_size,sen_len,512])# y=model(x,x,x,ask_mask)# print(y.shape)登录后复制
FeedForward
In [9]
class FeedForward(nn.Layer): def __init__(self,d_model,d_ff=2048,dropout=dropout): super(FeedForward, self).__init__() #两个全连接,一个ReLU self.model=nn.Sequential( nn.Linear(d_model,d_ff), nn.ReLU(), nn.Dropout(dropout), nn.Linear(d_ff,d_model) ) def forward(self,x): return self.model(x)# model=FeedForward(512,2048)# x=paddle.randn([batch_size,sen_len,512])# y=model(x)# print(y.shape)登录后复制
组装
EncoderLayer
In [10]
class EncoderLayer(nn.Layer): def __init__(self,d_model,heads,dropout=dropout): super(EncoderLayer, self).__init__() #归一化层 self.norm1=nn.LayerNorm(d_model) self.norm2=nn.LayerNorm(d_model) #多头自注意力层 self.attention=MutiHeadAttention(d_model,heads,dropout) #前馈层 self.feedforward=FeedForward(d_model,dropout=dropout) self.drop1=nn.Dropout(dropout) self.drop2=nn.Dropout(dropout) def forward(self,x,mask): y=self.norm1(x) #残差块,防止梯度消失 x=x+self.drop1(self.attention(y,y,y,mask)) y=self.norm2(x) #残差块,防止梯度消失 x=x+self.drop2(self.feedforward(y)) return x# model=EncoderLayer(d_model,heads)# x=paddle.randn([batch_size,sen_len,d_model])# y=model(x,ask_mask)# print(y.shape)登录后复制
DecoderLayer
In [11]
class DecoderLayer(nn.Layer): def __init__(self,d_model,heads,dropout=dropout): super(DecoderLayer, self).__init__() #归一化层 self.norm1=nn.LayerNorm(d_model) self.norm2=nn.LayerNorm(d_model) self.norm3=nn.LayerNorm(d_model) #掩码自注意力层与前馈层 self.attention1=MutiHeadAttention(d_model,heads,dropout) self.attention2=MutiHeadAttention(d_model,heads,dropout) self.feedforward=FeedForward(d_model,dropout=dropout) self.drop1=nn.Dropout(dropout) self.drop2=nn.Dropout(dropout) self.drop3=nn.Dropout(dropout) def forward(self,x,encoder_output,src_mask,trg_mask): #x=paddle.broadcast_to(x,encoder_output.shape) y=self.norm1(x) #残差块 #这里为多头注意力层 x=x+self.drop1(self.attention1(y,y,y,trg_mask)) y=self.norm2(x) #这里为掩码多头注意力,同时将encoder的output输入 x=x+self.drop2(self.attention2(y,encoder_output,encoder_output,src_mask)) y=self.norm3(x) #前馈 x=x+self.drop3(self.feedforward(y)) return x# model=DecoderLayer(d_model,heads)# x=paddle.randn([batch_size,sen_len,d_model])# e_output=paddle.randn([batch_size,sen_len,d_model])# y=model(x,e_output,ask_mask,ans_mask)# print(y.shape)登录后复制
定义拷贝函数
In [12]
import copydef clone_module(module,N): return nn.LayerList([copy.deepcopy(module) for i in range(N)])# module=EncoderLayer(d_model,heads)# print(clone_module(module,3))登录后复制
Encoder
In [13]
class Encoder(nn.Layer): def __init__(self,vocab_size,d_model,heads,N): super(Encoder, self).__init__() #总体的层数 self.N=N self.emb=Embedder(vocab_size,d_model) #位置编码层 self.posi_encoder=PositionalEncoder(d_model) #注意力加前馈多层重叠 self.layers=clone_module(EncoderLayer(d_model,heads),N) self.norm=nn.LayerNorm(d_model) def forward(self,src,mask): x=self.emb(src) x=self.posi_encoder(x) for i in range(self.N): x=self.layers[i](x,mask) x=self.norm(x) return x# model=Encoder(vocab_size,d_model,heads,N)# x=paddle.randn([batch_size,sen_len])# y=model(x.astype("int64"),ask_mask.astype("int64"))# print(y.shape)登录后复制
Decoder
In [14]
class Decoder(nn.Layer): def __init__(self,vocab_size,d_model,heads,N): super(Decoder, self).__init__() self.N=N self.emb=Embedder(vocab_size,d_model) self.posi_encoder=PositionalEncoder(d_model) self.layers=clone_module(DecoderLayer(d_model,heads),N) self.norm=nn.LayerNorm(d_model) def forward(self,trg,encoder_output,src_mask,trg_mask): x=self.emb(trg) x=self.posi_encoder(x) #调整数据类型 x,encoder_output=x.astype("float32"),encoder_output.astype("float32") for i in range(self.N): x=self.layers[i](x,encoder_output,src_mask,trg_mask) x=self.norm(x) return x# model=Decoder(vocab_size,d_model,heads,N)# x=paddle.randint(0,vocab_size,[batch_size,sen_len])# en_output=paddle.randn([batch_size,sen_len,d_model])# y=model(x.astype("int64"),en_output,ask_mask,ans_mask)# print(y.shape)登录后复制
Transformer
In [15]
class Transformer(nn.Layer): def __init__(self,vocab_size,d_model,heads,N): super(Transformer, self).__init__() #初始化 nn.initializer.set_global_initializer(nn.initializer.XavierNormal(),nn.initializer.Constant(0.)) #编码器 self.encoder=Encoder(vocab_size,d_model,heads,N) #解码器 self.decoder=Decoder(vocab_size,d_model,heads,N) #全连接 self.out=nn.Linear(d_model,vocab_size) def forward(self,src,trg,src_mask,trg_mask): encoder_output=self.encoder(src,src_mask) decoder_output=self.decoder(trg,encoder_output,src_mask,trg_mask) output=self.out(decoder_output) return output model=Transformer(vocab_size,d_model,heads,N) y=model(ask,ans,ask_mask,ans_mask)print(y.shape)登录后复制 In [16]
def trans(out): out=F.softmax(out,axis=-1) seq=out.argmax(axis=-1) sen=seq[100,:] sen=[words[i] for i in sen] sen=" ".join(sen) return sen登录后复制
开启训练
In []
num_epoch=1000learning_rate=1e-4pad=dic["pad"] model=Transformer(vocab_size,d_model,heads,N) opt=paddle.optimizer.Adam(parameters=model.parameters(),learning_rate=learning_rate,beta2=0.98,epsilon=1e-9)for epoch in range(num_epoch): for i,(src,trg) in enumerate(dataloader()): model.train() #获取掩码 src_mask,trg_mask=create_mask(src,trg) #获取预测值 pred=model(src,trg,src_mask,trg_mask) #展开 trg_=trg.reshape([-1]) #展开 pred_=pred.reshape([-1,pred.shape[-1]]) #求损失,并去除pad的影响 loss=F.cross_entropy(pred_,trg_,ignore_index=pad) opt.clear_grad() loss.backward() opt.step() if i%10==0: print("epoch:%d,i:%d,loss:%f,perlexity:%f"%(epoch,i,loss,math.exp(loss))) print(trans(pred)) #print(answer(model,index_data[random.randint(0,700),0])) if (epoch+1)%2==0: paddle.save(model.state_dict(),"work/transformer.pdparams")登录后复制
结果展示
In [19]
model=Transformer(vocab_size,d_model,heads,N) state_dict=paddle.load("work/transformer.pdparams") model.load_dict(state_dict) ask,ans=next(dataloader()) src_mask,trg_mask=create_mask(ask,ans) pred=model(ask,ans,src_mask,trg_mask) ask_1,ask_2,ask_3=ask[1],ask[10],ask[100] ask_1,ask_2,ask_3=[words[i] for i in ask_1],[words[i] for i in ask_2],[words[i] for i in ask_3] ask_1,ask_2,ask_3=" ".join(ask_1)," ".join(ask_2)," ".join(ask_3) ans_1,ans_2,ans_3=pred[1],pred[10],pred[100] ans_1,ans_2,ans_3=ans_1.argmax(-1),ans_2.argmax(-1),ans_3.argmax(-1) ans_1,ans_2,ans_3=[words[i] for i in ans_1],[words[i] for i in ans_2],[words[i] for i in ans_3] ans_1,ans_2,ans_3=" ".join(ans_1)," ".join(ans_2)," ".join(ans_3)print("Human1:",ask_1)print("Human2:",ans_1)print("##")print("Human1:",ask_2)print("Human2:",ans_2)print("##")print("Human1:",ask_3)print("Human2:",ans_3)登录后复制
Human1: eos pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad here do you did what sos Human2: sos oh everything jigglypuff ideas to an conversations the fish market disney land and giant robot fighting show haha pad pad pad pad pad pad pad pad pad pad push ## Human1: eos pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad like look saturday your does what sure sos Human2: sos saturday looks social good impersonate we shoot for regardless in the morning pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad push ## Human1: eos pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad it like you do work of lot a like sounds that sos Human2: sos well jigglypuff actually innovation pulled college photography but it s really expected pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad pad push登录后复制
进步与不足与彩蛋
可以看到结果还是喜人的,相较于上一期的Seqeq模型,我们采用了一种称为“注意力机制”的创新技术,显著提升了预测句子多样性和规范性的表现。这种改进使模型能够更加灵活地表达不同信息,并在保持准确性的同时增加了新颖性。然而,有时候也会出现一些小错误,比如频繁输出相同的单词。为了解决这一问题,我们可以尝试增加训练步骤的数量来优化“炼丹”过程,从而减少这类现象发生的频率。此外,我们还可以考虑使用时间维度的更精确处理方法,进一步提升模型性能。在下一期中,我们将复现李宏毅老师团队最新发布的StepGAN的研究成果。这款模型融合了生成对抗网络(Generative Adversarial Network, GAN)和深度学习(Deep Reinforcement Learning, DRL)的特点,并巧妙地结合了注意力机制的优势,使得其在文本生成方面具有极强的实用性。让我们一起期待这一创新模型如何进一步改善我们的预测任务!
Disadvantage(缺点)
positional encoding未能解决位置信息问题,而transformer主要处理词汇意义和相邻词的关系,对单词原始位置的关注不够。为了改善这一点,通过使用复杂的三角函数来缓解编码不足的问题。
以上就是『NLG学习』(二)教你搭建自己的Transformer的详细内容,更多请关注其它相关文章!
