Transformer

文章目录

  • Transformer
    • 1.理论
      • 1.1 Model Structure
      • 1.2 Multi-Head Attention & Scaled Dot-Product Attention
    • 请添加图片描述
    • 2.实验
      • 2.1 束搜索
      • 2.2 Issue

1.理论

1.1 Model Structure


1.2 Multi-Head Attention & Scaled Dot-Product Attention

2.实验

2.1 束搜索

束搜索过程示意图:



2.2 Issue

  1. 贪婪搜索和束搜索
    贪婪搜索和束搜索都是针对多个时间步,每一轮都要比较概率大小的,因此所有预测生成1个单词或者进行单词翻译的
    都谈不上贪婪搜索和束搜索(没有多个时间步),直接用predict=model(inputs)的也谈不上贪婪搜索和束搜索(没有每一轮比较概率大小).
    对于Seq2Seq和采用了序列模型的transformer来说,贪婪搜索和束搜索都应该用预测的单词覆盖填充的’SPPPP’中的’P’

    1. 对于翻译多个单词的任务,应该对于每个生成的单词设置循环

      1. 贪婪搜索:每个时间步生成一个单词的概率分布,取最大值,然后把这个值传给进行下一时间步,最后生成所有单词
      2. 束搜索(k=3):在每个时间步上预测k个max单词然后把这两个单词分别作为值传给进行下一时间步,
        当然,这样会进行kTk^TkT次预测,存储kTk^TkT个输出,最后取总概率最高的.
    2. 对于预测生成多个单词的任务,应该对于每个生成的单词设置循环
      1. 贪婪搜索:在输入时间步之后,每个输出时间步生成一个单词的概率分布,取最大值,
        然后把这个值传给进行下一时间步,最后生成所有单词
      2. 束搜索(k=3):在输入时间步之后,每个输出时间步上预测k个max单词,然后把这两个单词分别作为值
        传给进行下一时间步,当然,这样会进行kTk^TkT次预测,存储kTk^TkT个输出,最后取总概率最高的.
  2. 为什么Seq2Seq和基于序列模型的transformer直接用predict=model(enc_inputs, dec_inputs=‘SPPPPP’)的效果不好,其中transformer效果尤其差,而其他模型还不错?
    直接用predict=model(enc_inputs, dec_inputs=‘SPPPPP’)既不算贪婪搜索也不算束搜索,因为这样只在最后才比较概率大小,而贪婪搜索和束搜索每轮都要计算

    1. RNN/LSTM等模型不需要’SPPPP’填充,因此不会受到空白信息影响,可以直接生成,
      而Seq2Seq/transformer会受到’SPPPP’影响,所以效果不好.
    2. 其中,序列模型和RNN/LSTM类似,一个时间步对应一个单词,一个decoder时间步对应初始输入为’P’,
      上一次的时间步输出可以影响下一时间步生成,所以效果不好不坏
    3. 而transformer每次输入输出都是以整个句子为单位,所以不存在上一次的时间步输出可以影响下一时间步生成,所以效果尤其差,必须用循环依次生成
  3. 为什么束搜索中有时候其他句子总体评价更高?
    模型过于复杂,训练样本太少,导致过拟合.

"""
Task: 基于Transformer的句子翻译
Author: ChengJunkai @github.com/Cheng0829
Email: chengjunkai829@gmail.com
Date: 2022/09/17
Reference: Tae Hwan Jung(Jeff Jung) @graykode
"""import numpy as np
import torch, time, itertools, os, sys
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt# S: 表示开始进行解码输入的符号.
# E: 表示结束进行解码输出的符号.
# P: 当前批次数据大小小于时间步长时将填充空白序列的符号'''1.数据预处理'''
def pre_process(sentences):# P在第一个,方便处理src_sequence = ['P']src_sequence.extend(sentences[0].split())src_list = []'''如果用list(set(word_sequence))来去重,得到的将是一个随机顺序的列表(因为set无序),这样得到的字典不同,保存的上一次训练的模型很有可能在这一次不能用(比如上一次的模型预测碰见i:0,love:1,就输出you:2,但这次模型you在字典3号位置,也就无法输出正确结果)'''for word in src_sequence:if word not in src_list:src_list.append(word)src_dict = {w:i for i,w in enumerate(src_list)}src_dict_size = len(src_dict)src_len = len(sentences[0].split()) # length of source# P在第一个,方便处理tgt_sequence = ['P']tgt_sequence.extend(sentences[1].split()+sentences[2].split())tgt_list = []'''如果用list(set(word_sequence))来去重,得到的将是一个随机顺序的列表(因为set无序),这样得到的字典不同,保存的上一次训练的模型很有可能在这一次不能用(比如上一次的模型预测碰见i:0,love:1,就输出you:2,但这次模型you在字典3号位置,也就无法输出正确结果)'''for word in tgt_sequence:if word not in tgt_list:tgt_list.append(word)tgt_dict = {w:i for i,w in enumerate(tgt_list)}number_dict = {i:w for i,w in enumerate(tgt_dict)}tgt_dict_size = len(tgt_dict)tgt_len = len(sentences[1].split()) # length of targetreturn src_dict,src_dict_size,tgt_dict,number_dict,tgt_dict_size,src_len,tgt_len'''根据句子数据,构建词元的输入向量'''
def make_batch(sentences):input_batch = [[src_dict[n] for n in sentences[0].split()]]output_batch = [[tgt_dict[n] for n in sentences[1].split()]]target_batch = [[tgt_dict[n] for n in sentences[2].split()]]input_batch = torch.LongTensor(np.array(input_batch)).to(device)output_batch = torch.LongTensor(np.array(output_batch)).to(device)target_batch = torch.LongTensor(np.array(target_batch)).to(device)# print(input_batch, output_batch,target_batch) # tensor([[0, 1, 2, 3, 4, 5]]) tensor([[3, 1, 0, 2, 4]]) tensor([[1, 0, 2, 4, 5]])return input_batch, output_batch,target_batchdef get_position_encoding_table(n_position, d_model): # inputs: (src_len+1, d_model) or (tgt_len+1, d_model)pos_table = np.zeros((n_position, d_model))for pos in range(n_position):for i in range(d_model):tmp = pos / np.power(10000, 2*(i//2) / d_model)if i % 2 == 0: # 偶数为正弦pos_table[pos][i] = np.sin(tmp) # (7 or 6, 512)else:# 奇数为余弦pos_table[pos][i] = np.cos(tmp) # (7 or 6, 512)return torch.FloatTensor(pos_table).to(device)def get_attn_pad_mask(seq_q, seq_k, dict): '''mask大小和(len_q,len_k)一致,是为了在点积注意力中,与torch.matmul(Q,K)的大小一致'''# (seq_q, seq_k): (dec_inputs, enc_inputs)# dec_inputs:[batch_size, tgt_len] # [1,5]# enc_inputs:[batch_size, src_len] # [1,6]batch_size, len_q = seq_q.size() # 1,5batch_size, len_k = seq_k.size() # 1,6"""Tensor.data.eq(element)eq即equal,对Tensor中所有元素进行判断,和element相等即为True,否则为False,返回二值矩阵Examples:>>> tensor = torch.FloatTensor([[1, 2, 3], [4, 5, 6]])>>> tensor.data.eq(1) tensor([[ True, False, False],[False, False, False]])"""# eq(zero) is PAD tokenpad_attn_mask = seq_k.data.eq(dict['P']).unsqueeze(1) # 升维 enc: [1,6] -> [1,1,6]# 矩阵扩充: enc: pad_attn_mask: [1,1,6] -> [1,5,6]return pad_attn_mask.expand(batch_size, len_q, len_k) # batch_size, len_q, len_k'''Attention = Softmax(Q * K^T) * V '''
def Scaled_Dot_Product_Attention(Q, K, V, attn_mask): # Q_s: [batch_size, n_heads, len_q, d_k] # [1,8,5,64]# K_s: [batch_size, n_heads, len_k, d_k] # [1,8,6,64]# attn_mask: [batch_size, n_heads, len_q, len_k] # [1,8,5,6]"""torch.matmul(Q, K)torch.matmul是tensor的乘法,输入可以是高维的.当输入是都是二维时,就是普通的矩阵乘法.当输入有多维时,把多出的一维作为batch提出来,其他部分做矩阵乘法.Exeamples:>>> a = torch.ones(3,4)>>> b = torch.ones(4,2)>>> torch.matmul(a,b).shapetorch.Size([3,2])   >>> a = torch.ones(5,3,4)>>> b = torch.ones(4,2)>>> torch.matmul(a,b).shapetorch.Size([5,3,2])>>> a = torch.ones(2,5,3)>>> b = torch.ones(1,3,4)>>> torch.matmul(a,b).shapetorch.Size([2,5,4])"""# [1,8,5,64] * [1,8,64,6] -> [1,8,5,6]# scores : [batch_size, n_heads, len_q, len_k]scores = torch.matmul(Q, K.transpose(2,3)) / np.sqrt(d_k) # divided by scale"""scores.masked_fill_(attn_mask, -1e9) 由于scores和attn_mask维度相同,根据attn_mask中的元素值,把和attn_mask中值为True的元素的位置相同的scores元素的值赋为-1e9"""scores.masked_fill_(attn_mask, -1e9)# 'P'的scores元素值为-1e9, softmax值即为0softmax = nn.Softmax(dim=-1) # 求行的softmaxattn = softmax(scores) # [1,8,6,6]# [1,8,6,6] * [1,8,6,64] -> [1,8,6,64]context = torch.matmul(attn, V) # [1,8,6,64]return context, attnclass MultiHeadAttention(nn.Module):# dec_enc_attn(dec_outputs, enc_outputs, enc_outputs, dec_enc_attn_mask)def __init__(self):super().__init__()self.W_Q = nn.Linear(d_model, d_k*n_heads) # (512, 64*8) # d_q必等于d_kself.W_K = nn.Linear(d_model, d_k*n_heads) # (512, 64*8) # 保持维度不变self.W_V = nn.Linear(d_model, d_v*n_heads) # (512, 64*8)self.linear = nn.Linear(n_heads*d_v, d_model)self.layer_norm = nn.LayerNorm(d_model)def forward(self, Q, K, V, attn_mask):# dec_outputs: [batch_size, tgt_len, d_model] # [1,5,512]# enc_outputs: [batch_size, src_len, d_model] # [1,6,512]# dec_enc_attn_mask: [batch_size, tgt_len, src_len] # [1,5,6]# q/k/v: [batch_size, len_q/k/v, d_model]residual, batch_size = Q, len(Q)'''用n_heads=8把512拆成64*8,在不改变计算成本的前提下,让各注意力头相互独立,更有利于学习到不同的特征'''# Q_s: [batch_size, len_q, n_heads, d_q] # [1,5,8,64]# new_Q_s: [batch_size, n_heads, len_q, d_q] # [1,8,5,64]Q_s = self.W_Q(Q).view(batch_size, -1, n_heads, d_k).transpose(1,2)  # K_s: [batch_size, n_heads, len_k, d_k] # [1,8,6,64]K_s = self.W_K(K).view(batch_size, -1, n_heads, d_k).transpose(1,2)  # V_s: [batch_size, n_heads, len_k, d_v] # [1,8,6,64]V_s = self.W_V(V).view(batch_size, -1, n_heads, d_v).transpose(1,2)  # attn_mask : [1,5,6] -> [1,1,5,6] -> [1,8,5,6]# attn_mask : [batch_size, n_heads, len_q, len_k]attn_mask = attn_mask.unsqueeze(1).repeat(1, n_heads, 1, 1) # context: [batch_size, n_heads, len_q, d_v]# attn: [batch_size, n_heads, len_q(=len_k), len_k(=len_q)]# context: [1,8,5,64] attn: [1,8,5,6]context, attn = Scaled_Dot_Product_Attention(Q_s, K_s, V_s, attn_mask)"""contiguous() 连续的contiguous: view只能用在连续(contiguous)的变量上.如果在view之前用了transpose, permute等,需要用contiguous()来返回一个contiguous copy"""# context: [1,8,5,64] -> [1,5,512]context = context.transpose(1, 2).contiguous().view(batch_size, -1, n_heads * d_v)# context: [1,5,512] -> [1,5,512]output = self.linear(context)"""nn.LayerNorm(output) 样本归一化和对所有样本的某一特征进行归一化的BatchNorm不同,LayerNorm是对每个样本进行归一化,而不是一个特征Tips:归一化Normalization和Standardization标准化区别:Normalization(X[i]) = (X[i] - np.min(X)) / (np.max(X) - np.min(X))Standardization(X[i]) = (X[i] - np.mean(X)) / np.var(X)"""output = self.layer_norm(output + residual)return output, attn class Position_wise_Feed_Forward_Networks(nn.Module):def __init__(self):super().__init__()'''输出层相当于1*1卷积层,也就是全连接层'''"""nn.Conv1din_channels应该理解为嵌入向量维度,out_channels才是卷积核的个数(厚度)"""# 512 -> 2048self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1)# 2048 -> 512self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1)self.layer_norm = nn.LayerNorm(d_model)def forward(self, inputs):# enc_outputs: [batch_size, source_len, d_model] # [1,6,512]residual = inputs relu = nn.ReLU()# output: 512 -> 2048 [1,2048,6]output = relu(self.conv1(inputs.transpose(1, 2)))# output: 2048 -> 512 [1,6,512]output = self.conv2(output).transpose(1, 2)return self.layer_norm(output + residual)class EncoderLayer(nn.Module):def __init__(self):super(EncoderLayer, self).__init__()self.enc_attn = MultiHeadAttention()self.pos_ffn = Position_wise_Feed_Forward_Networks()def forward(self, enc_outputs, enc_attn_mask):# enc_attn_mask: [1,6,6]# enc_outputs to same Q,K,V# enc_outputs: [batch_size, source_len, d_model] # [1, 6, 512]enc_outputs, attn = self.enc_attn(enc_outputs, \enc_outputs, enc_outputs, enc_attn_mask) # enc_outputs: [batch_size , len_q , d_model]enc_outputs = self.pos_ffn(enc_outputs) return enc_outputs, attnclass DecoderLayer(nn.Module):def __init__(self):super().__init__()self.dec_attn = MultiHeadAttention()self.dec_enc_attn = MultiHeadAttention()self.pos_ffn = Position_wise_Feed_Forward_Networks()def forward(self, dec_outputs, enc_outputs, dec_attn_mask, dec_enc_attn_mask):dec_outputs, dec_attn = \self.dec_attn(dec_outputs, dec_outputs, dec_outputs, dec_attn_mask)# dec_outputs: [1, 5, 512]   dec_enc_attn: [1, 8, 5, 6]dec_outputs, dec_enc_attn = \self.dec_enc_attn(dec_outputs, enc_outputs, enc_outputs, dec_enc_attn_mask)# 相当于两个全连接层 512 -> 2048 -> 512dec_outputs = self.pos_ffn(dec_outputs)return dec_outputs, dec_attn, dec_enc_attnclass Encoder(nn.Module):def __init__(self):super().__init__()# 输入向量的嵌入矩阵self.src_emb = nn.Embedding(src_dict_size, d_model).to(device)# 6个编码层self.layers = nn.ModuleList([EncoderLayer().to(device) for _ in range(n_layers)])def forward(self, enc_inputs): # enc_inputs: [batch_size, source_len] # [1, 6]input = [src_dict[i] for i in sentences[0].split()] # [0,1,2,3,4,5]'''加入pos_emb的意义: 如果不加,所有位置的单词都将有完全相同的影响,体现不出序列的特点'''# 可学习的输入向量嵌入矩阵 + 不可学习的序列向量矩阵# enc_outputs: [1, 6, 512]'''embbeding和linear不同,emb之后会加一个维度'''enc_outputs = self.src_emb(enc_inputs) + position_encoding[input] # 屏蔽P,返回一个 [batch_size,src_len,src_len]=[1,6,6]的二值矩阵enc_attn_mask = get_attn_pad_mask(enc_inputs, enc_inputs, src_dict)enc_attns = []for layer in self.layers:# enc_outputs既是输入,也是输出enc_outputs, enc_attn = layer(enc_outputs, enc_attn_mask)enc_attns.append(enc_attn)return enc_outputs, enc_attnsclass Decoder(nn.Module):def __init__(self):super().__init__()self.tgt_emb = nn.Embedding(tgt_dict_size, d_model)self.layers = nn.ModuleList([DecoderLayer() for _ in range(n_layers)])def forward(self, dec_inputs, enc_inputs, enc_outputs): # dec_inputs : [batch_size, target_len] [1,5]input = [tgt_dict[i] for i in sentences[1].split()]dec_outputs = self.tgt_emb(dec_inputs)# 为输入句子的每一个单词(不去重)加入序列信息# dec_outputs: [1, 5, 512]dec_outputs = dec_outputs + position_encoding[input] # 屏蔽pad字符,返回一个 [batch_size,tgt_len,tgt_len]=[1,5,5]的二值矩阵dec_attn_mask = get_attn_pad_mask(dec_inputs, dec_inputs, tgt_dict)# 屏蔽pad字符和之后时刻的信息for i in range(0, len(dec_inputs[0])):for j in range(i+1, len(dec_inputs[0])):dec_attn_mask[0][i][j] = True # 使softmax值为0# 第二个多注意力机制,输入来自encoder和decoder 屏蔽encoder中的pad字符dec_enc_attn_mask = get_attn_pad_mask(dec_inputs, enc_inputs, src_dict) # [1,5,6]dec_attns, dec_enc_attns = [], []for layer in self.layers:dec_outputs, dec_attn, dec_enc_attn = \layer(dec_outputs, enc_outputs, dec_attn_mask, dec_enc_attn_mask)dec_attns.append(dec_attn)dec_enc_attns.append(dec_enc_attn)return dec_outputs, dec_attns, dec_enc_attns'''2.构建Transformer模型'''
class Transformer(nn.Module):def __init__(self):super().__init__()self.encoder = Encoder()self.decoder = Decoder()self.projection = nn.Linear(d_model, tgt_dict_size, bias=False)def forward(self, dec_inputs, enc_inputs):enc_outputs, enc_attns = self.encoder(enc_inputs)dec_outputs, dec_attns, dec_enc_attns \= self.decoder(dec_inputs, enc_inputs, enc_outputs)# model_outputs: [batch_size, tgt_len, tgt_dict_size]model_outputs = self.projection(dec_outputs) # [1,5,7]model_outputs = model_outputs.squeeze(0)return model_outputs, enc_attns, dec_attns, dec_enc_attns'''贪婪搜索'''
def Greedy_Search(model, enc_inputs, start_symbol): # start_symbol = tgt_dict['S']'''依次生成tgt_len个目标单词,每生成一个单词都要进行一次完整的transformer计算,最后依次取第i个位置上概率最大的单词,生成新的dec_inputs贪婪搜索输出之后,新的dec_inputs重新和其他参数输入模型,最后生成predict'''padding_inputs = 'S' + ' P' * (tgt_len-1)# [1,5]dec_inputs = torch.Tensor([[tgt_dict[i] for i in padding_inputs.split()]]).to(device).type_as(enc_inputs.data)next_symbol = start_symboli = 0while True:'''由enc_inputs和'S P P P P'生成i,然后i赋值给下一轮的dec_inputs:'S i P P P'然后生成want->'S i want P P' ······,生成beer->'S i want a beer'其实就是生成target_batch,然后错位赋值给dec_inputs,这个刚好符合训练模型时target_batch对应sentence[2],dec_inputs对应的sentence[1],enc_inputs对应的sentence[0]'''dec_inputs[0][i] = next_symboloutputs, _, _, _ = model(dec_inputs, enc_inputs)    predict = outputs.squeeze(0).max(dim=-1, keepdim=False)[1]next_symbol = predict[i].item()i = i + 1# 超过最大长度或者有终止符则退出循环if next_symbol == tgt_dict['E'] or i > max_len:breakoutputs, _, _, _ = model(dec_inputs, enc_inputs)    predict = outputs.squeeze(0).max(dim=-1, keepdim=False)[1]return predict# 为束搜索构造连续重复矩阵
def repeat(inputs,k=2):"""连续重复Examples:>>> a = torch.tensor([[1,2,3],[4,5,6]])>>> print(repeat(a))[[1,2,3],[1,2,3],[4,5,6],[4,5,6]]>>> import torch>>> print(torch.repeat(a))[[1,2,3],[4,5,6],[1,2,3],[4,5,6]]        """tmp = torch.zeros(inputs.size(0)*k, inputs.size(1), inputs.size(2)).type_as(inputs.data)pos = 0while pos < len(inputs):tmp[pos*k] = inputs[pos]for i in range(1,k):tmp[pos*k+i] = inputs[pos]pos = pos + 1return tmp'''束搜索'''
def Beam_Search(model, enc_inputs, start_symbol, k=2):padding_inputs = 'S' + (tgt_len-1)*' P'# dec_inputs:[1,5]dec_inputs = torch.Tensor([[tgt_dict[i] for i in padding_inputs.split()]]).to(device).type_as(enc_inputs.data)# all_dec_inputs用来存储每一种dec_inputs# all_dec_inputs:[1,1,5]all_dec_inputs = dec_inputs.unsqueeze(0)# 由于第一个单词被定为'S',所以其实每轮生成的实际结果数是2,4,8,16,16(最后一轮复制为32,但因为马上就结束循环,不会再分别赋值)for i in range(tgt_len):# 每一个单词,all_dec_inputs都要重复k次,存放新生成的k**i个结果# 注意,repeat函数实现的是连续重复,而不是toch.repeat那样的整体间断重复all_dec_inputs = repeat(all_dec_inputs,k) # 对于第i个单词,以步长k遍历all_dec_inputs(即前一轮的所有dec_inputs)# 分别将其作为模型输入for j in range(0,len(all_dec_inputs),k):# print(j)dec_inputs = all_dec_inputs[j] outputs, _, _, _ = model(dec_inputs, enc_inputs)# 排序,得到索引indices = outputs.sort(descending=True).indices # [5,7]# 提取第i个单词的第k个可能,赋值给all_dec_inputs的第j+pos个样本# (因为连续重复,所以all_dec_inputs中第j个dec_inputs生成的# 输出就分布在j~j+k个dec_inputs)for pos in range(k):if i < tgt_len - 1:# i+1表示留给下一轮用,这和贪婪搜索中的思想一致all_dec_inputs[j+pos][0][i+1] = indices[i][pos]print(all_dec_inputs)'''评判所有dec_inputs,选出输出概率最大的'''result = []for dec_inputs in all_dec_inputs:sum = 0outputs, _, _, _ = model(dec_inputs, enc_inputs) indexs = outputs.squeeze(0).max(dim=-1, keepdim=False)[1]for i in range(tgt_len):# 计算各个样本输出的单词概率之和sum = sum + outputs.data[i][indexs[i]]result.append(sum.item())'''可能过拟合输出错误解'''max_index = result.index(max(result))predict = all_dec_inputs[max_index]return predictif __name__ == '__main__':chars = 30 * '*'# sentences = ['ich mochte ein bier P', 'S i want a beer', 'i want a beer E']sentences = ['我 要 喝 啤 酒 P', 'S i want a beer', 'i want a beer E']device = ['cuda:0' if torch.cuda.is_available() else 'cpu'][0]d_model = 512  # Embedding Size 嵌入向量维度d_ff = 2048  # FeedForward dimensiond_k = d_v = 64  # dimension of K(=Q), Vn_layers = 6  # number of Encoder of Decoder Layer 编解码器层数n_heads = 8  # number of heads in Multi-Head Attention 多注意力机制头数max_len = 5'''1.数据预处理'''src_dict,src_dict_size,tgt_dict,number_dict,tgt_dict_size,src_len,tgt_len = pre_process(sentences)position_encoding = get_position_encoding_table(max(src_dict_size, tgt_dict_size), d_model)enc_inputs, dec_inputs, target_batch = make_batch(sentences)'''2.构建模型'''model = Transformer()model.to(device)criterion = nn.CrossEntropyLoss()# Adam的效果非常不好optimizer = optim.SGD(model.parameters(), lr=0.001)if os.path.exists('model_param.pt') == True:# 加载模型参数到模型结构model.load_state_dict(torch.load('model_param.pt', map_location=device))'''3.训练'''print('{}\nTrain\n{}'.format('*'*30, '*'*30))loss_record = []for epoch in range(1000):optimizer.zero_grad()outputs, enc_attns, dec_attns, dec_enc_attns \= model(dec_inputs, enc_inputs)outputs = outputs.to(device)loss = criterion(outputs, target_batch.contiguous().view(-1))loss.backward()optimizer.step()if loss >= 0.01: # 连续30轮loss小于0.01则提前结束训练loss_record = []else:loss_record.append(loss.item())if len(loss_record) == 30:torch.save(model.state_dict(), 'model_param.pt')break    if (epoch + 1) % 100 == 0:print('Epoch:', '%04d' % (epoch + 1), 'Loss = {:.6f}'.format(loss))torch.save(model.state_dict(), 'model_param.pt')'''4.测试'''print('{}\nTest\n{}'.format('*'*30, '*'*30))# 贪婪算法predict = Greedy_Search(model, enc_inputs, start_symbol=tgt_dict["S"])# 束搜索算法predict = Beam_Search(model, enc_inputs, start_symbol=tgt_dict["S"])for word in sentences[0].split():if word not in ['S', 'P', 'E']:print(word, end='')print(' ->',end=' ')for i in predict.data.squeeze():if number_dict[int(i)] not in ['S', 'P', 'E'] :print(number_dict[int(i)], end=' ')

NLP之基于Transformer的句子翻译相关推荐

  1. 基于Transformer的中英文翻译

    基于Transformer的机器翻译 机器翻译是利用计算机将一种自然语言(源语言)转换为另一种自然语言(目标语言)的过程. 本项目是机器翻译领域主流模型 Transformer 的 PaddlePad ...

  2. 无需卷积,完全基于Transformer的首个视频理解架构TimeSformer出炉

    选自Facebook AI 机器之心编译 编辑:小舟.陈萍 Facebook AI 提出新型视频理解架构:完全基于Transformer,无需卷积,训练速度快.计算成本低. TimeSformer 是 ...

  3. 重磅开源!首个基于Transformer的视频理解网络来啦!

    部分转载自:机器之心  |  编辑:小舟.陈萍 Facebook AI 提出新型视频理解架构:完全基于Transformer,无需卷积,训练速度快.计算成本低.最近由Facebook提出的首个完全基于 ...

  4. 【综述】基于Transformer的视频语言预训练

    关注公众号,发现CV技术之美 ▊ 1. 论文和代码地址 Survey: Transformer based Video-Language Pre-training 论文地址:https://arxiv ...

  5. NLP——基于transformer 的翻译系统

    文章目录 基于transformer 的翻译系统 1. 数据处理 1.1 英文分词 1.2 中文分词 1.3 生成字典 1.4 数据生成器 2. 构建模型 2.1 构造建模组件 layer norm层 ...

  6. 最新综述:基于Transformer的NLP预训练模型已经发展到何种程度?

    ©作者 | 机器之心编辑部 来源 | 机器之心 Transformer 为自然语言处理领域带来的变革已无需多言.近日,印度国立理工学院.生物医学人工智能创业公司 Nference.ai 的研究者全面调 ...

  7. NLP实操手册: 基于Transformer的深度学习架构的应用指南(综述)

    翻译来自百分点认知智能实验室 易显维 桂安春 本文翻译自The NLP Cookbook: Modern Recipes for Transformer based Deep Learning Arc ...

  8. 基于Transformer实现英语-->西班牙语的翻译任务

    基于Transformer实现英语–>西班牙语的翻译任务 该项目基于PaddlePaddle框架完成,项目直达:基于Transformer实现英语–>西班牙语的翻译任务 作者信息: Git ...

  9. 基于Transformer的数字子母翻译

    基于Transformer的数字字母翻译 内容转自添加链接描述 文章目录 基于Transformer的数字字母翻译 1. 任务描述 2. 代码文件结构 3. mydata.py 4. myutil.p ...

最新文章

  1. 爱奇艺视频千万级生产 Kubernetes 集群优化实践!
  2. 几个受益终身的英文缩写
  3. JS学习笔记2-JavaScript 语法
  4. 最新性能测试:Kafka、Pulsar 和 Pravega 哪个最强?
  5. linux安装qt4 creator,ubuntu14.04下安装qt4.8.6 +qt creator
  6. C语言博客作业---嵌套循环
  7. 消灭非稳态噪音的利器 - AI 降噪
  8. 通俗理解:实际用户ID/有效用户ID/保存的设置用户ID(saved set-user-ID)
  9. ios实现video自动播放
  10. php doc生成pdf文件怎么打开乱码,phpexcel 导出pdf文件乱码,该如何解决
  11. win10 nas搭建_Windows Server 2019搭建NAS的一些总结
  12. 鸡嗉囊炎有哪些症状 什么药防治鸡嗉囊肿大
  13. Google TV 来了
  14. multiple definition of `main'
  15. 辨析三种一致性:缓存一致、内存一致、数据一致
  16. “产教融合,共享生态” CIE 2017中国IT教育博鳌论坛圆满召开
  17. 2022-05-粤语-九声六调
  18. 第9期 | 家系、肿瘤临床基因组/外显子组数据分析实战
  19. 中国有多少java程序员_中国有多少个程序员?
  20. Vue进阶(六十四):iframe更改src后页面未刷新问题解决

热门文章

  1. 次坐标从0开始_全站仪使用方法及坐标计算讲解
  2. html打赏代码,利用弹出窗口实现打赏的代码
  3. matlab倍频程设计,[转载]1/3倍频程及Matlab程序实现
  4. webserver日志中\xCF\xE3\xB8\xDB\xCA\xAE\xB4\xF3\xCE\xC4\xBB\xAF\xB7\xFB\xBA\xC5这种形式原因及处理
  5. 唤客猫SCRM功能详解(一)
  6. python列表元素的查找和添加_Python list列表查找元素
  7. memcached分布式原理与实现
  8. php 冒泡查找 降序 随机数 封装,又一个PHP实现的冒泡排序算法分享
  9. Python实战——爬虫
  10. 超大屏幕模拟鼠标,投影屏幕触摸屏,会场投影屏互动触摸事件