直观理解并使用Tensorflow实现Seq2Seq模型的注意机制(上)

本文涉及的产品
模型训练 PAI-DLC,5000CU*H 3个月
交互式建模 PAI-DSW,每月250计算时 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
简介: 直观理解并使用Tensorflow实现Seq2Seq模型的注意机制

采用带注意机制的序列序列结构进行英印地语神经机器翻译

Seq2seq模型构成了机器翻译、图像和视频字幕、文本摘要、聊天机器人以及任何你可能想到的包括从一个数据序列到另一个数据序列转换的任务的基础。如果您曾使用过谷歌Translate,或与Siri、Alexa或谷歌Assistant进行过互动,那么你就是序列对序列(seq2seq)神经结构的受益者。

我们这里的重点是机器翻译,基本上就是把一个句子x从一种语言翻译成另一种语言的句子y。机器翻译是seq2seq模型的主要用例,注意机制对机器翻译进行了改进。关于这类主题的文章通常涉及用于实现的大代码段和来自多个库的大量API调用,对概念本身没有直观的理解。在这方面,我们既要讲求理论,也要讲求执行。除了实现之外,我们还将详细了解seq2seq体系结构和注意力的每个组件表示什么。本文中使用的代码可以在最后的资源列表中找到。

目标

在Tensorflow中实现、训练和测试一个英语到印地语机器翻译模型。

对编码器、解码器、注意机制的作用形成直观透彻的理解。

讨论如何进一步改进现有的模型。

读数据集

首先,导入所有需要的库。在这个实现中使用的英语到印地语语料库可以在Kaggle找到。一个名为“Hindi_English_Truncated_Corpus”的文件。将下载csv "。请确保在pd.read_csv()函数中放置了正确的文件路径,该路径对应于文件系统中的路径。

import numpy as np
import pandas as pd
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
import tensorflow as tf
from sklearn.model_selection import train_test_split
import time
from matplotlib import pyplot as plt
import os
import re
data = pd.read_csv("./Hindi_English_Truncated_Corpus.csv")
english_sentences = data["english_sentence"]
hindi_sentences = data["hindi_sentence"]

让我们快速看看我们正在处理的数据集的类型。这是相当简单的。

640.png

数据预处理

在我们继续我们的编码器,解码器和注意力实现之前,我们需要预处理我们的数据。请注意,预处理步骤也依赖于我们处理的数据类型。例如,在这里考虑的数据集中,也有带有空字符串的句子。我们需要相应地处理这类案例。如果使用其他数据集,也可能需要一些额外或更少的步骤。预处理步骤如下:

在单词和标点符号之间插入空格

如果手头上的句子是英语,我们就用空格替换除了(a-z, A-Z, “.”, “?”, “!”, “,”)

句子中去掉多余的空格,关键字“sentencestart”和“sentenceend”分别添加到句子的前面和后面,让我们的模型明确地知道句子开始和结束。

每个句子的以上三个任务都是使用preprocess_sentence()函数实现的。我们还在开始时初始化了所有的超参数和全局变量。请阅读下面的超参数和全局变量。我们将在需要时使用它们。

# Global variables and Hyperparameters
num_words = 10000
oov_token = '<UNK>'
english_vocab_size = num_words + 1
hindi_vocab_size = num_words + 1
MAX_WORDS_IN_A_SENTENCE = 16
test_ratio = 0.2
BATCH_SIZE = 512
embedding_dim = 64
hidden_units = 1024
learning_rate = 0.006
epochs = 100
def preprocess_sentence(sen, is_english):
if (type(sen) != str):
 return ''
sen = sen.strip('.')
# insert space between words and punctuations
sen = re.sub(r"([?.!,¿;।])", r" \1 ", sen)
sen = re.sub(r'[" "]+', " ", sen)
# For english, replacing everything with space except (a-z, A-Z, ".", "?", "!", ",", "'")
if(is_english == True):
 sen = re.sub(r"[^a-zA-Z?.!,¿']+", " ", sen)
 sen = sen.lower()
sen = sen.strip()
sen = 'sentencestart ' + sen + ' sentenceend'
sen = ' '.join(sen.split())
return sen

对包含英语句子和印地语句子的每个数据点进行循环,确保不考虑带有空字符串的句子,并且句子中的最大单词数不大于MAX_WORDS_IN_A_SENTENCE的值。这一步是为了避免我们的矩阵是稀疏的。

下一步是对文本语料库进行向量化。具体来说,fit_on_texts()为每个单词分配一个唯一的索引。texts_to_sequences()将一个文本句子转换为一个数字列表或一个向量,其中数字对应于单词的唯一索引。pad_sequences()通过添加刚好足够数量的oov_token(从vocab token中提取)来确保所有这些向量最后都具有相同的长度,使每个向量具有相同的长度。tokenize_statements()封装了上面这些功能。

接下来,我们从完整的数据集中得到训练集,然后对训练集进行批处理。我们训练模型所用的句子对总数为51712。

# Loop through each datapoint having english and hindi sentence
processed_e_sentences = []
processed_h_sentences = []
for (e_sen, h_sen) in zip(english_sentences, hindi_sentences):
processed_e_sen = preprocess_sentence(e_sen, True)
processed_h_sen = preprocess_sentence(h_sen, False)
if(processed_e_sen == '' or processed_h_sen == '' or processed_e_sen.count(' ') > (MAX_WORDS_IN_A_SENTENCE-1) or processed_h_sen.count(' ') > (MAX_WORDS_IN_A_SENTENCE-1)):
 continue
processed_e_sentences.append(processed_e_sen)
processed_h_sentences.append(processed_h_sen)
print("Sentence examples: ")
print(processed_e_sentences[0])
print(processed_h_sentences[0])
print("Length of English processed sentences: " + str(len(processed_e_sentences)))
print("Length of Hindi processed sentences: " + str(len(processed_h_sentences)))
def tokenize_sentences(processed_sentences, num_words, oov_token):
tokenizer = Tokenizer(num_words = num_words, oov_token = oov_token)
tokenizer.fit_on_texts(processed_sentences)
word_index = tokenizer.word_index
sequences = tokenizer.texts_to_sequences(processed_sentences)
sequences = pad_sequences(sequences, padding = 'post')
return word_index, sequences, tokenizer
english_word_index, english_sequences, english_tokenizer = tokenize_sentences(processed_e_sentences, num_words, oov_token)
hindi_word_index, hindi_sequences, hindi_tokenizer = tokenize_sentences(processed_h_sentences, num_words, oov_token)
# split into traning and validation set
english_train_sequences, english_val_sequences, hindi_train_sequences, hindi_val_sequences = train_test_split(english_sequences, hindi_sequences, test_size = test_ratio)
BUFFER_SIZE = len(english_train_sequences)
# Batching the training set
dataset = tf.data.Dataset.from_tensor_slices((english_train_sequences, hindi_train_sequences)).shuffle(BUFFER_SIZE)
dataset = dataset.batch(BATCH_SIZE, drop_remainder = True)
print("No. of batches: " + str(len(list(dataset.as_numpy_iterator()))))

编码器Encoder

Seq2seq架构在原论文中涉及到两个长短期内存(LSTM)。一个用于编码器,另一个用于解码器。请注意,在编码器和解码器中,我们将使用GRU(门控周期性单元)来代替LSTM,因为GRU的计算能力更少,但结果与LSTM几乎相同。Encoder涉及的步骤:

输入句子中的每个单词都被嵌入并表示在具有embedding_dim(超参数)维数的不同空间中。换句话说,您可以说,在具有embedding_dim维数的空间中,词汇表中的单词的数量被投影到其中。这一步确保类似的单词(例如。boat & ship, man & boy, run & walk等)都位于这个空间附近。这意味着“男人”这个词和“男孩”这个词被预测的几率几乎一样(不是完全一样),而且这两个词的意思也差不多。

接下来,嵌入的句子被输入GRU。编码器GRU的最终隐藏状态成为解码器GRU的初始隐藏状态。编码器中最后的GRU隐藏状态包含源句的编码或信息。源句的编码也可以通过所有编码器隐藏状态的组合来提供[我们很快就会发现,这一事实对于注意力的概念的存在至关重要]。

640.png

class Encoder(tf.keras.Model):
def __init__(self, english_vocab_size, embedding_dim, hidden_units):
 super(Encoder, self).__init__()
 self.embedding = tf.keras.layers.Embedding(english_vocab_size, embedding_dim)
 self.gru = tf.keras.layers.GRU(hidden_units, return_sequences = True, return_state = True)
def call(self, input_sequence):
 x = self.embedding(input_sequence)
 encoder_sequence_output, final_encoder_state = self.gru(x)
 #Dimensions of encoder_sequence_output => (BATCH_SIZE, MAX_WORDS_IN_A_SENTENCE, hidden_units)
 #Dimensions of final_encoder_state => (BATCH_SIZE, hidden_units)
 return encoder_sequence_output, final_encoder_state
# initialize our encoder
encoder = Encoder(english_vocab_size, embedding_dim, hidden_units)


解码器Decoder ( 未使用注意力机制)

注意:在本节中,我们将了解解码器的情况下,不涉及注意力机制。这对于理解稍后与解码器一起使用的注意力的作用非常重要。

解码器GRU网络是生成目标句的语言模型。最终的编码器隐藏状态作为解码器GRU的初始隐藏状态。第一个给解码器GRU单元来预测下一个的单词是一个像“sentencestart”这样的开始标记。这个标记用于预测所有num_words数量的单词出现的概率。训练时使用预测的概率张量和实际单词的一热编码来计算损失。这种损失被反向传播以优化编码器和解码器的参数。同时,概率最大的单词成为下一个GRU单元的输入。重复上述步骤,直到出现像“sentenceend”这样的结束标记。

640.png

这种方法的问题是:

信息瓶颈:如上所述,编码器的最终隐藏状态成为解码器的初始隐藏状态。这就造成了信息瓶颈,因为源句的所有信息都需要压缩到最后的状态,这也可能会偏向于句子末尾的信息,而不是句子中很久以前看到的信息。

解决方案:我们解决了上述问题,不仅依靠编码器的最终状态来获取源句的信息,还使用了编码器所有输出的加权和。那么,哪个编码器的输出比另一个更重要?注意力机制就是为了解决这个问题。

目录
相关文章
|
1月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
将Keras训练好的.hdf5模型转换为TensorFlow的.pb模型,然后再转换为TensorRT支持的.uff格式,并提供了转换代码和测试步骤。
82 3
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
|
4天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
19 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
4天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
20 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
20天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
65 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
2月前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
108 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
1月前
|
机器学习/深度学习 移动开发 TensorFlow
深度学习之格式转换笔记(四):Keras(.h5)模型转化为TensorFlow(.pb)模型
本文介绍了如何使用Python脚本将Keras模型转换为TensorFlow的.pb格式模型,包括加载模型、重命名输出节点和量化等步骤,以便在TensorFlow中进行部署和推理。
76 0
|
3月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
79 0
|
3月前
|
C# 开发者 前端开发
揭秘混合开发新趋势:Uno Platform携手Blazor,教你一步到位实现跨平台应用,代码复用不再是梦!
【8月更文挑战第31天】随着前端技术的发展,混合开发日益受到开发者青睐。本文详述了如何结合.NET生态下的两大框架——Uno Platform与Blazor,进行高效混合开发。Uno Platform基于WebAssembly和WebGL技术,支持跨平台应用构建;Blazor则让C#成为可能的前端开发语言,实现了客户端与服务器端逻辑共享。二者结合不仅提升了代码复用率与跨平台能力,还简化了项目维护并增强了Web应用性能。文中提供了从环境搭建到示例代码的具体步骤,并展示了如何创建一个简单的计数器应用,帮助读者快速上手混合开发。
82 0
|
3月前
|
开发者 算法 虚拟化
惊爆!Uno Platform 调试与性能分析终极攻略,从工具运用到代码优化,带你攻克开发难题成就完美应用
【8月更文挑战第31天】在 Uno Platform 中,调试可通过 Visual Studio 设置断点和逐步执行代码实现,同时浏览器开发者工具有助于 Web 版本调试。性能分析则利用 Visual Studio 的性能分析器检查 CPU 和内存使用情况,还可通过记录时间戳进行简单分析。优化性能涉及代码逻辑优化、资源管理和用户界面简化,综合利用平台提供的工具和技术,确保应用高效稳定运行。
83 0
|
3月前
|
前端开发 开发者 设计模式
揭秘Uno Platform状态管理之道:INotifyPropertyChanged、依赖注入、MVVM大对决,帮你找到最佳策略!
【8月更文挑战第31天】本文对比分析了 Uno Platform 中的关键状态管理策略,包括内置的 INotifyPropertyChanged、依赖注入及 MVVM 框架。INotifyPropertyChanged 方案简单易用,适合小型项目;依赖注入则更灵活,支持状态共享与持久化,适用于复杂场景;MVVM 框架通过分离视图、视图模型和模型,使状态管理更清晰,适合大型项目。开发者可根据项目需求和技术栈选择合适的状态管理方案,以实现高效管理。
43 0

热门文章

最新文章