吴恩达深度学习_5_Week3序列模型和注意力机制:神经机器翻译

神经机器翻译


1、将人类可读的日期转换为机器可读的日期
2、神经机器翻译与注意力
3、可视化注意力


第五门课:序列模型
第三周:序列模型和注意力机制

您将构建神经机器翻译 (NMT) 模型,以将人类可读日期(“2009 年 6 月 25 日”)转换为机器可读日期(“2009 年 6 月 25 日”)。您将使用注意力模型来执行此操作,注意力模型是最复杂的序列到序列模型之一。
这款笔记本是与NVIDIA的深度学习研究所共同制作的。

from keras.layers import Bidirectional, Concatenate, Permute, Dot, Input, LSTM, Multiply
from keras.layers import RepeatVector, Dense, Activation, Lambda
from keras.optimizers import Adam
from keras.utils import to_categorical
from keras.models import load_model, Model
import keras.backend as K
import numpy as np

from faker import Faker
import random
from tqdm import tqdm
from babel.dates import format_date
from nmt_utils import *
import matplotlib.pyplot as plt

一、将人类可读的日期转换为机器可读的日期

您将在此处构建的模型可用于从一种语言翻译成另一种语言,例如从英语翻译成印地语。然而,语言翻译需要大量的数据集,并且通常需要在 GPU 上进行数天的训练。为了让您在不使用大量数据集的情况下试验这些模型,我们将改用更简单的“日期转换”任务。
网络将输入以各种可能格式书写的日期(例如“1958 年 8 月 29 日”、“1968 年 3 月 30 日”、“1987 年 6 月 24 日”),并将其转换为标准化的机器可读日期(例如“1958-08-29”、“1968-03-30”、“1987-06-24”)。我们将让网络学习以通用的机器可读格式 YYYY-MM-DD 输出日期。

1、数据集

我们将在包含 10000 个人类可读日期及其等效的、标准化的、机器可读日期的数据集上训练模型。让我们运行以下单元格来加载数据集并打印一些示例。

m = 10000
dataset, human_vocab, machine_vocab, inv_machine_vocab = load_dataset(m)

dataset[:10]

您已加载:
1、dataset:(人类可读日期、机器可读日期)的元组列表
2、human_vocab:一个 Python 字典,将人类可读日期中使用的所有字符映射到整数值索引
3、machine_vocab:一个 Python 字典,将机器可读日期中使用的所有字符映射到整数值索引。这些指数不一定与human_vocab一致。
4、inv_machine_vocab:machine_vocab的逆字典,从索引映射回字符。
让我们对数据进行预处理,并将原始文本数据映射到索引值中。我们还将使用 Tx=30(我们假设这是人类可读日期的最大长度;如果我们得到更长的输入,我们将不得不截断它)和 Ty=10(因为“YYYY-MM-DD”的长度为 10 个字符)。

Tx = 30
Ty = 10
X, Y, Xoh, Yoh = preprocess_data(dataset, human_vocab, machine_vocab, Tx, Ty)

print("X.shape:", X.shape)
print("Y.shape:", Y.shape)
print("Xoh.shape:", Xoh.shape)
print("Yoh.shape:", Yoh.shape)

您现在拥有:
X:训练集中人类可读日期的处理版本,其中每个字符都由通过human_vocab映射到字符的索引替换。每个日期都进一步填充到 Tx 中
具有特殊字符的值(<填充>)。X.shape = (m, Tx)
Y:训练集中机器可读日期的处理版本,其中每个字符都替换为它在machine_vocab中映射到的索引。你应该有 Y.shape = (m, Ty)。
Xoh:X的一个热门版本,“1”条目的索引映射到字符,这要归功于human_vocab。Xoh.shape = (m, Tx, len(human_vocab))
Yoh:Y 的一个热门版本,“1”条目的索引映射到字符,这要归功于 machine_vocab。Yoh.shape = (m, Tx, len(machine_vocab))。这里,len(machine_vocab) = 11,因为有 11 个字符(‘-’ 以及 0-9)。

让我们再看一些预处理训练示例的示例。随意使用下面单元格中的索引来导航数据集并查看源/目标日期的预处理方式。

index = 7
print("Source date:", dataset[index][0])
print("Target date:", dataset[index][1])
print()
print("Source after preprocessing (indices):", X[index])
print("Target after preprocessing (indices):", Y[index])
print()
print("Source after preprocessing (one-hot):", Xoh[index])
print("Target after preprocessing (one-hot):", Yoh[index])

二、神经机器翻译与注意力

如果你必须将一本书的段落从法语翻译成英语,你不会阅读整个段落,然后合上书并翻译。即使在翻译过程中,您也会阅读/重读并专注于与您正在写下的英语部分相对应的法语段落部分。
注意力机制告诉神经机器翻译模型在任何步骤中都应该注意的位置。

1、注意力机制

在这一部分中,您将实现讲座视频中介绍的注意力机制。下图提醒您模型的工作原理。左图显示了注意力模型。右图显示了一个“注意力”步骤如何计算注意力变量α⟨t,t′⟩,用于计算上下文变量 context⟨t⟩对于输出中的每个时间步长 ( t=1,…,Ty ).
在这里插入图片描述
在这里插入图片描述
以下是您可能会注意到的模型的一些属性:

  1. 此模型中有两个独立的 LSTM(见左图)。因为图片底部的那个是双向 LSTM,并且位于注意力机制之前,所以我们将其称为预注意力 Bi-LSTM。图顶部的 LSTM 位于注意力机制之后,因此我们将其称为后注意力 LSTM。预注意 Bi-LSTM 通过 Tx时间步长;后注意力 LSTM 通过 Ty时间步长。
  2. 后注意 LSTM 传递 s⟨t⟩,c⟨t⟩从一个时间步长到下一个时间步长。在讲座视频中,我们只使用了一个基本的RNN作为激活后序列模型,因此RNN捕获的状态输出激活s⟨t⟩ .但是,由于我们在这里使用的是 LSTM,因此 LSTM 同时具有输出激活 s⟨t⟩和隐藏的单元格状态 c⟨t⟩.然而,与之前的文本生成示例(例如第 1 周的恐龙)不同,在此模型中,激活后 LSTM 在时间 t不会接受特定生成的 y⟨t−1⟩作为输入;只需要 s⟨t⟩和 c⟨t⟩作为输入。我们以这种方式设计模型,因为(与相邻字符高度相关的语言生成不同)在 YYYY-MM-DD 日期中,前一个字符和下一个字符之间没有那么强的依赖性。
  3. 我们使用 a⟨t⟩=[a→⟨t⟩;a←⟨t⟩]表示预注意Bi-LSTM的正向和后向激活的串联。
  4. 右图使用 RepeatVector 节点复制 s⟨t−1⟩的值 Tx次,然后串联以连接 s⟨t−1⟩和 a⟨t⟩计算 e⟨t,t′,然后通过 softmax 来计算 α⟨t,t′⟩.我们将在下面解释如何在 Keras 中使用 RepeatVector 和 Concatenation。

让我们实现这个模型。您将首先实现两个函数:one_step_attention() 和 model()。
1) one_step_attention():在步骤 t,给定 Bi-LSTM 的所有隐藏状态 ( [a<1>,a<2>,…,a]) 和第二个 LSTM 的先前隐藏状态 ( s<t−1> ),one_step_attention() 将计算注意力权重 ( [α<t,1>,α<t,2>,…,α<t,Tx>]) 并输出上下文向量(有关详细信息,请参见图 1(右)):
在这里插入图片描述
请注意,我们在此笔记本上下文中表示关注⟨t⟩.在讲座视频中,上下文表示为 c⟨t⟩,但在这里我们称之为 context⟨t⟩以避免与(注意力后)LSTM的内部存储单元变量混淆,该变量有时也表示为c⟨t⟩ .
2) model():实现整个模型。它首先通过 Bi-LSTM 运行输入以返回 [a<1>,a<2>,…,a]然后,它调用 one_step_attention() Ty times(for 循环)。在此循环的每次迭代中,它都会给出计算出的上下文向量 c到第二个 LSTM,并通过 softmax 激活的密集层运行 LSTM 的输出,以生成预测

练习:实现 one_step_attention()。函数 model() 将调用 one_step_attention() Ty 中的层使用 for 循环,重要的是所有 Ty副本具有相同的权重。也就是说,它不应该每次都重新启动权重。换句话说,所有 Ty步骤应具有共享权重。以下是在 Keras 中实现具有可共享权重的层的方法:

  1. 定义图层对象(例如,作为全局变量)。
  2. 在传播输入时调用这些对象。
    我们已将您需要的图层定义为全局变量。请运行以下单元格以创建它们。请查看 Keras 文档,以确保您了解这些层是什么:RepeatVector()Concatenate()Dense()Activation()Dot()
# Defined shared layers as global variables
repeator = RepeatVector(Tx)
concatenator = Concatenate(axis=-1)
densor1 = Dense(10, activation = "tanh")
densor2 = Dense(1, activation = "relu")
activator = Activation(softmax, name='attention_weights') # We are using a custom softmax(axis = 1) loaded in this notebook
dotor = Dot(axes = 1)

现在您可以使用这些层来实现 one_step_attention()。为了将 Keras 张量对象 X 传播到这些层之一,请使用 layer(X)(或 layer([X,Y]),如果它需要多个输入,例如 densor(X) 将通过上面定义的 Dense(1) 层传播 X。

执行一个注意步骤:输出计算为注意权重的点积的上下文向量“alphas”和 Bi-LSTM 的隐藏状态“a”。
参数:
    a -- Bi-LSTM 的隐藏状态输出,形状为 (m, Tx, 2*n_a) 的 numpy-array
    s_prev -- (后注意)LSTM 的先前隐藏状态,形状为 (m, n_s) 的 numpy-array
返回:context -- 上下文向量,下一个(后衰减)LSTM 单元的输入
# GRADED FUNCTION: one_step_attention
def one_step_attention(a, s_prev):
    # Use repeator to repeat s_prev to be of shape (m, Tx, n_s) so that you can concatenate it with all hidden states "a" 
    s_prev = repeator(s_prev)
    # Use concatenator to concatenate a and s_prev on the last axis 
    concat = concatenator([a, s_prev])
    # Use densor1 to propagate concat through a small fully-connected neural network to compute the "intermediate energies" variable e. 
    e = densor1(concat)
    # Use densor2 to propagate e through a small fully-connected neural network to compute the "energies" variable energies. 
    energies = densor2(e)
    # Use "activator" on "energies" to compute the attention weights "alphas" (≈ 1 line)
    alphas = activator(energies)
    # Use dotor together with "alphas" and "a" to compute the context vector to be given to the next (post-attention) LSTM-cell 
    context = dotor([alphas, a])

    return context

在对 model() 函数进行编码后,您将能够检查 one_step_attention() 的预期输出。
练习:实现 model(),如图 2 和上面的文本所示。同样,我们定义了全局层,这些层将共享要在 model() 中使用的权重。

n_a = 32
n_s = 64
post_activation_LSTM_cell = LSTM(n_s, return_state = True)
output_layer = Dense(len(machine_vocab), activation=softmax)

现在您可以使用这些图层 Tyfor 循环中的次数来生成输出,并且它们的参数不会重新初始化。您将必须执行以下步骤:
1、将输入传播到双向 LSTM 中
2、迭代 t=0,…,Ty−1:

  • 在 [α<t,1>,α<t,2>,…,α<t,Tx>] 上调用 one_step_attention()和 s<t−1>获取上下文向量 context.
  • 提供上下文到注意力后 LSTM 细胞。记住在之前的隐藏状态 s⟨t−1 中传递⟩和细胞状态 c⟨t−1⟩
  • 使用 initial_state= [以前的隐藏状态,以前的单元状态]。取回新的隐藏状态 s和新的单元状态 c.
  • 将 softmax 图层应用于 s,获取输出。
  • 通过将输出添加到输出列表来保存输出。
    3、创建 Keras 模型实例,它应该有三个输入(“inputs”、s<0>和 c<0>) 并输出“输出”列表。
参数:
    Tx -- 输入序列的长度
    Ty -- 输出序列的长度
    n_a -- Bi-LSTM 的隐藏状态大小
    n_s -- 后注意力 LSTM 的隐藏状态大小
    human_vocab_size -- python 字典 “human_vocab” 的大小
    machine_vocab_size -- python 字典 “machine_vocab” 的大小
返回:model -- Keras 模型实例
# GRADED FUNCTION: model
def model(Tx, Ty, n_a, n_s, human_vocab_size, machine_vocab_size):
    
    # Define the inputs of your model with a shape (Tx,)
    # Define s0 and c0, initial hidden state for the decoder LSTM of shape (n_s,)
    X = Input(shape=(Tx, human_vocab_size))
    s0 = Input(shape=(n_s,), name='s0')
    c0 = Input(shape=(n_s,), name='c0')
    s = s0
    c = c0
    
    # Initialize empty list of outputs
    outputs = []

    # Step 1: Define your pre-attention Bi-LSTM. Remember to use return_sequences=True. (≈ 1 line)
    a = Bidirectional(LSTM(n_a, return_sequences=True))(X)

    # Step 2: Iterate for Ty steps
    for t in range(Ty):

        # Step 2.A: Perform one step of the attention mechanism to get back the context vector at step t (≈ 1 line)
        context = one_step_attention(a, s)

        # Step 2.B: Apply the post-attention LSTM cell to the "context" vector.
        # Don't forget to pass: initial_state = [hidden state, cell state] (≈ 1 line)
        s, _, c = post_activation_LSTM_cell(context, initial_state = [s, c])

        # Step 2.C: Apply Dense layer to the hidden state output of the post-attention LSTM (≈ 1 line)
        out = output_layer(s)

        # Step 2.D: Append "out" to the "outputs" list (≈ 1 line)
        outputs.append(out)

    # Step 3: Create model instance taking three inputs and returning the list of outputs. (≈ 1 line)
    model = Model(inputs=[X,s0,c0],outputs=outputs)

    return model

model = model(Tx, Ty, n_a, n_s, len(human_vocab), len(machine_vocab))
model.summary()   #这里应该是excepted有误

在这里插入图片描述
像往常一样,在 Keras 中创建模型后,您需要编译它并定义要使用的损失、优化器和指标。使用自定义 Adam 优化器(学习率 = 0.005,β1=0.9)编译模型(categorical_crossentropy损失, 𝛽2=0.999、衰减 = 0.01) 和 [‘accuracy’] 指标:

opt = Adam(lr=0.0005, beta_1=0.9, beta_2=0.999, decay=0.01)
model.compile(loss = 'categorical_crossentropy',optimizer=opt, metrics = ['accuracy'])

最后一步是定义所有输入和输出以拟合模型:
1、你已经有形状的 X (m=10000,Tx=30)包含训练示例。
2、您需要创建 s0 和 c0 以使用 0 初始化post_activation_LSTM_cell。
3、给定您编码的 model(),您需要“输出”是 11 个形状元素(m、T_y)的列表。因此:outputs[i][0], …, outputs[i][Ty] 表示对应于 i 的真实标签(字符)训练示例 (X[i])。更一般地说,outputs[i][j] 是第 j 个的真实标签第 i 个字符训练示例。

s0 = np.zeros((m, n_s))
c0 = np.zeros((m, n_s))
outputs = list(Yoh.swapaxes(0,1))

model.fit([Xoh, s0, c0], outputs, epochs=1, batch_size=100)

在训练时,您可以看到输出的 10 个位置中每个位置的损耗和准确性。下表给出了一个示例,说明如果批处理有 2 个示例,精度可能是多少:
在这里插入图片描述
我们运行了这个模型更长的时间,并节省了权重。运行下一个单元格以加载我们的权重。(通过训练几分钟的模型,您应该能够获得类似精度的模型,但加载我们的模型将节省您的时间。

model.load_weights('models/model.h5')

EXAMPLES = ['3 May 1979', '5 April 09', '21th of August 2016', 'Tue 10 Jul 2007', 'Saturday May 9 2018', 'March 3 2001', 'March 3rd 2001', '1 March 2001']
for example in EXAMPLES:
    
    source = string_to_int(example, Tx, human_vocab)
    source = np.array(list(map(lambda x: to_categorical(x, num_classes=len(human_vocab)), source))).swapaxes(0,1)
    prediction = model.predict([source, s0, c0])
    prediction = np.argmax(prediction, axis = -1)
    output = [inv_machine_vocab[int(i)] for i in prediction]
    
    print("source:", example)
    print("output:", ''.join(output))

您还可以更改这些示例以使用您自己的示例进行测试。下一部分将让你更好地了解注意力机制在做什么,即在生成特定输出字符时,网络正在关注输入的哪一部分。

三、可视化注意力

由于问题的固定输出长度为 10,因此也可以使用 10 个不同的 softmax 单元来生成输出的 10 个字符来执行此任务。但注意力模型的一个优点是,输出的每个部分(比如月份)都知道它只需要依赖于输入的一小部分(输入中给出月份的字符)。我们可以可视化输出的哪一部分正在查看输入的哪一部分。
考虑将“2018 年 5 月 9 日星期六”翻译成“2018-05-09”的任务。如果我们可视化计算出的 α⟨t,t′⟩我们得到这个:
在这里插入图片描述
请注意,输出如何忽略输入的“星期六”部分。没有一个输出时间步长会过多关注输入的那部分。我们还看到,9 被翻译为 09,May 被正确翻译成 05,输出注意翻译所需的输入部分。年份主要要求它注意输入的“18”,以便生成“2018”。
从网络获取激活
现在让我们可视化网络中的注意力值。我们将通过网络传播一个示例,然后可视化 α⟨t,t′ 的值⟩

model.summary()

浏览上面 model.summary() 的输出。您可以看到名为 attention_weights 的图层输出形状为 (m, 30, 1) 的 alpha,然后dot_2计算每个时间步长 t=0,…,Ty−1 的上下文向量.让我们从这一层获取激活。
函数 attention_map() 从模型中提取注意力值并绘制它们。

attention_map = plot_attention_map(model, human_vocab, inv_machine_vocab, "Tuesday 09 Oct 1993", num = 7, n_s = 64)

在生成的图上,您可以观察预测输出中每个字符的注意力权重值。检查此图并检查网络关注的位置是否对您有意义。
在日期翻译应用程序中,您将观察到,大多数时候注意力有助于预测年份,并且对预测日/月没有太大影响。

记住的内容

  1. 机器翻译模型可用于从一个序列映射到另一个序列。它们不仅可用于翻译人类语言(如法语-英语>英语),还可用于日期格式翻译等任务。
  2. 注意力机制允许网络在产生输出的特定部分时专注于输入中最相关的部分。
  3. 使用注意力机制的网络可以从长度为 Tx 的输入进行转换到长度为 Ty 的输出 ,其中 Tx和 Ty可以不同。
  4. 您可以可视化注意力权重 α⟨t,t′⟩ 以查看网络在生成每个输出时正在关注的内容。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值