【博主使用的python版本:3.6.8】
本次没有额外的资料下载
Packages
ort tensorflow as tf import pandas as pd import time import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.layers import Embedding, MultiHeadAttention, Dense, Input, Dropout, LayerNormalization from transformers import DistilBertTokenizerFast #, TFDistilBertModel from transformers import TFDistilBertForTokenClassification from tqdm import tqdm_notebook as tqdm
1 - 位置编码
在顺序到序列任务中,数据的相对顺序对其含义非常重要。当你训练顺序神经网络(如RNN)时,你按顺序将输入输入到网络中。有关数据顺序的信息会自动输入到模型中。但是,在训练转换器网络时,会一次性将数据全部输入到模型中。虽然这大大减少了训练时间,但没有关于数据顺序的信息。这就是位置编码有用的地方 - 您可以专门编码输入的位置,并使用以下正弦和余弦公式将它们传递到网络中:
- d是词嵌入和位置编码的维度
- pos是单词的位置。
- i指位置编码的每个不同维度。
正弦和余弦方程的值足够小(介于 -1 和 1 之间),因此当您将位置编码添加到单词嵌入时,单词嵌入不会明显失真。位置编码和单词嵌入的总和最终是输入到模型中的内容。结合使用这两个方程有助于变压器网络关注输入数据的相对位置。请注意,虽然在讲座中,Andrew 使用垂直向量,但在此作业中,所有向量都是水平的。所有矩阵乘法都应相应调整。
1.1 - 正弦角和余弦角
通过计算正弦和余弦方程的内项,获取用于计算位置编码的可能角度:
练习 1 - get_angles
实现函数 get_angles() 来计算正弦和余弦位置编码的可能角度
def get_angles(pos, i, d): """ 获取位置编码的角度 Arguments: pos -- 包含位置的列向量[[0], [1], ...,[N-1]] i -- 包含维度跨度的行向量 [[0, 1, 2, ..., M-1]] d(integer) -- 编码大小 Returns: angles -- (pos, d) 数组 """ angles = pos/ (np.power(10000, (2 * (i//2)) / np.float32(d))) return angles
我们测试一下:
def get_angles_test(target): position = 4 d_model = 16 pos_m = np.arange(position)[:, np.newaxis] dims = np.arange(d_model)[np.newaxis, :] result = target(pos_m, dims, d_model) assert type(result) == np.ndarray, "你必须返回一系列数组集合" assert result.shape == (position, d_model), f"防止错误我们希望: ({position}, {d_model})" assert np.sum(result[0, :]) == 0 assert np.isclose(np.sum(result[:, 0]), position * (position - 1) / 2) even_cols = result[:, 0::2] odd_cols = result[:, 1::2] assert np.all(even_cols == odd_cols), "奇数列和偶数列的子矩阵必须相等" limit = (position - 1) / np.power(10000,14.0/16.0) assert np.isclose(result[position - 1, d_model -1], limit ), f"组后的值必须是 {limit}" print("