本文基于 transformers库,调用bert模型,对中文、英文的稠密向量进行探究
开始之前还是要说下废话,主要是想吐槽下,为啥写这个东西呢?因为我找了很多文章要么不是不清晰,要么就是基于pytorch,所以特地写了这篇基于tensorflow2.0+的
运行环境
这个环境 没有严格要求,仅供参考
win10 + python 3.8 + tensorflow 2.9.1 + transformers 4.20.1
导入库
from transformers import AutoTokenizer, TFAutoModel
import tensorflow as tf
import matplotlib.pyplot as plt
加载模型
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = TFAutoModel.from_pretrained(model_name,
output_hidden_states=True)
输入测试句子
utt = ['今天的月亮又大又圆', '月亮真的好漂亮啊', '今天去看电影吧', "爱情睡醒了,天琪抱着小贝进酒店", "侠客行风万里"]
inputs = tokenizer(utt, return_tensors="tf", padding="max_length", truncation=True, max_length=64)
outputs = model(inputs)
hidden_states = outputs[2]
解释下输出(hidden_states):
- The layer number (13 layers)
- The batch number (5 sentence) 也就是输入句子的个数
- The word / token number (64 tokens in our sentence) 也就是max_length
- The hidden unit / feature number (768 features)
疑惑点:
1.为啥是13层?bert不是12层吗?
第一层是输入的嵌入层,其余12层才是bert的
打印出出看下shape:
print("Number of layers:", len(hidden_states), " (initial embeddings + 12 BERT layers)")
layer_i = 0
print("Number of batches:", len(hidden_states[layer_i]))
batch_i = 0
print("Number of tokens:", len(hidden_states[layer_i][batch_i]))
token_i = 0
print("Number of hidden units:", len(hidden_states[layer_i][batch_i][token_i]))
查看下第一个句子第五个词在第五层的表示
batch_i = 0
token_i = 5
layer_i = 5
vec = hidden_states[layer_i][batch_i][token_i]
嗯,看下分布吧
plt.figure(figsize=(10, 10))
plt.hist(vec, bins=200)
plt.show()
现在多个句子的张量做一些改动
因为 _hidden_states_是元组,所以现在要把他的维度嵌入到张量中
sentence_embeddings = tf.stack(hidden_states, axis=0)
print(f"sentence_embeddings.shape : {sentence_embeddings.shape}")
调换维度,使每个词都有13层的嵌入表示
sentence_embeddings_perm = tf.transpose(sentence_embeddings, perm=[1, 2, 0, 3])
print(f"sentence_embeddings_perm.shape : {sentence_embeddings_perm.shape}")
获取词的稠密向量
第一种方式:拼接后四层的稠密向量
for sentence_embedding in sentence_embeddings_perm:
print(f"sentence_embedding.shape: {sentence_embedding.shape}")
token_vecs_cat = []
for token_embedding in sentence_embedding:
print(f"token_embedding.shape : {token_embedding.shape}")
cat_vec = tf.concat([token_embedding[-1], token_embedding[-2], token_embedding[-3], token_embedding[-4]], axis=0)
print(f"cat_vec.shape : {cat_vec.shape}")
token_vecs_cat.append(cat_vec)
print(f"len(token_vecs_cat) : {len(token_vecs_cat)}")
第二种方式:加和后四层的稠密向量
for sentence_embedding in sentence_embeddings_perm:
print(f"sentence_embedding.shape: {sentence_embedding.shape}")
token_vecs_cat = []
for token_embedding in sentence_embedding:
print(f"token_embedding.shape : {token_embedding.shape}")
cat_vec = sum(token_embedding[-4:])
print(f"cat_vec.shape : {cat_vec.shape}")
token_vecs_cat.append(cat_vec)
print(f"len(token_vecs_cat) : {len(token_vecs_cat)}")
获取句子的稠密向量
平均每个token 倒数第二层的稠密向量
token_vecs = sentence_embeddings[-2]
print(f"token_vecs.shape : {token_vecs.shape}")
sentences_embedding = tf.reduce_mean(token_vecs, axis=1)
print(f"sentences_embedding.shape : {sentences_embedding.shape}")
相似度探讨
不同句子间的相似度
tensor_test = sentences_embedding[0]
consine_sim_tensor = tf.keras.losses.cosine_similarity(tensor_test, sentences_embedding)
print(f"consine_sim_tensor : {consine_sim_tensor}")
探讨下相同词bank在不同上下文时其vector的相似度
utt = ["After stealing money from the bank vault, the bank robber was seen fishing on the Mississippi river bank."]
inputs = tokenizer(utt, return_tensors="tf", padding="max_length", truncation=True, max_length=22)
"""
0 [CLS]
1 after
2 stealing
3 money
4 from
5 the
6 bank
7 vault
8 ,
9 the
10 bank
11 robber
12 was
13 seen
14 fishing
15 on
16 the
17 mississippi
18 river
19 bank
20 .
21 [SEP]
bank单词的位置分别在6, 10, 19
"""
outputs = model(inputs)
hidden_states = outputs[2]
tokens_embedding = tf.reduce_sum(hidden_states[-4:], axis=0)
bank_vault = tokens_embedding[0][6]
bank_robber = tokens_embedding[0][10]
river_bank = tokens_embedding[0][19]
consine_sim_tensor = tf.keras.losses.cosine_similarity(bank_vault, [bank_robber, river_bank])
print(f"consine_sim_tensor : {consine_sim_tensor}")
可以看出bank_vault(银行金库)和bank_robber(银行抢劫犯)中的bank相似度更高些,合理!
完整代码
from transformers import AutoTokenizer, TFAutoModel
import tensorflow as tf
import matplotlib.pyplot as plt
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = TFAutoModel.from_pretrained(model_name,
output_hidden_states=True)
utt = ['今天的月亮又大又圆', '月亮真的好漂亮啊', '今天去看电影吧', "爱情睡醒了,天琪抱着小贝进酒店", "侠客行风万里"]
inputs = tokenizer(utt, return_tensors="tf", padding="max_length", truncation=True, max_length=64)
outputs = model(inputs)
hidden_states = outputs[2]
"""
解释下输出(hidden_states):
1. The layer number (13 layers)
2. The batch number (5 sentence) 也就是输入句子的个数
3. The word / token number (64 tokens in our sentence) 也就是max_length
4. The hidden unit / feature number (768 features)
疑惑点:
1.为啥是13层?bert不是12层吗?
第一层是输入的嵌入层,其余12层才是bert的
"""
print("Number of layers:", len(hidden_states), " (initial embeddings + 12 BERT layers)")
layer_i = 0
print("Number of batches:", len(hidden_states[layer_i]))
batch_i = 0
print("Number of tokens:", len(hidden_states[layer_i][batch_i]))
token_i = 0
print("Number of hidden units:", len(hidden_states[layer_i][batch_i][token_i]))
token_i = 5
layer_i = 5
vec = hidden_states[layer_i][batch_i][token_i]
plt.figure(figsize=(10, 10))
plt.hist(vec, bins=200)
plt.show()
sentence_embeddings = tf.stack(hidden_states, axis=0)
print(f"sentence_embeddings.shape : {sentence_embeddings.shape}")
sentence_embeddings_perm = tf.transpose(sentence_embeddings, perm=[1, 2, 0, 3])
print(f"sentence_embeddings_perm.shape : {sentence_embeddings_perm.shape}")
for sentence_embedding in sentence_embeddings_perm:
print(f"sentence_embedding.shape: {sentence_embedding.shape}")
token_vecs_cat = []
for token_embedding in sentence_embedding:
print(f"token_embedding.shape : {token_embedding.shape}")
cat_vec = tf.concat([token_embedding[-1], token_embedding[-2], token_embedding[-3], token_embedding[-4]], axis=0)
print(f"cat_vec.shape : {cat_vec.shape}")
token_vecs_cat.append(cat_vec)
print(f"len(token_vecs_cat) : {len(token_vecs_cat)}")
for sentence_embedding in sentence_embeddings_perm:
print(f"sentence_embedding.shape: {sentence_embedding.shape}")
token_vecs_cat = []
for token_embedding in sentence_embedding:
print(f"token_embedding.shape : {token_embedding.shape}")
cat_vec = sum(token_embedding[-4:])
print(f"cat_vec.shape : {cat_vec.shape}")
token_vecs_cat.append(cat_vec)
print(f"len(token_vecs_cat) : {len(token_vecs_cat)}")
token_vecs = sentence_embeddings[-2]
print(f"token_vecs.shape : {token_vecs.shape}")
sentences_embedding = tf.reduce_mean(token_vecs, axis=1)
print(f"sentences_embedding.shape : {sentences_embedding.shape}")
tensor_test = sentences_embedding[0]
consine_sim_tensor = tf.keras.losses.cosine_similarity(tensor_test, sentences_embedding)
print(f"consine_sim_tensor : {consine_sim_tensor}")
utt = ["After stealing money from the bank vault, the bank robber was seen fishing on the Mississippi river bank."]
inputs = tokenizer(utt, return_tensors="tf", padding="max_length", truncation=True, max_length=22)
"""
0 [CLS]
1 after
2 stealing
3 money
4 from
5 the
6 bank
7 vault
8 ,
9 the
10 bank
11 robber
12 was
13 seen
14 fishing
15 on
16 the
17 mississippi
18 river
19 bank
20 .
21 [SEP]
bank单词的位置分别在6, 10, 19
"""
outputs = model(inputs)
hidden_states = outputs[2]
tokens_embedding = tf.reduce_sum(hidden_states[-4:], axis=0)
bank_vault = tokens_embedding[0][6]
bank_robber = tokens_embedding[0][10]
river_bank = tokens_embedding[0][19]
consine_sim_tensor = tf.keras.losses.cosine_similarity(bank_vault, [bank_robber, river_bank])
print(f"consine_sim_tensor : {consine_sim_tensor}")
Original: https://blog.csdn.net/weixin_43730035/article/details/125819761
Author: 何强棒棒
Title: 基于tensorflow2.0+使用bert获取中文词、句向量并进行相似度分析
相关阅读
Title: TensorFlow实现自注意力机制(Self-attention)
TensorFlow实现自注意力机制(Self-attention)
*
- 自注意力机制(Self-attention)
-
+ 计算机视觉中的自注意力
- Tensorflow实现自注意力模块
自注意力机制(Self-attention)
自注意力机制 (Self-attention) 随着自然语言处理 (Natural Language Processing, NLP) 模型(称为"Transformer")的引入而变得流行。在诸如语言翻译之类的NLP应用程序中,模型通常需要逐字阅读句子以理解它们,然后再产生输出。Transformer问世之前使用的神经网络是递归神经网络 (Recurrent Neural Network, RNN) 或者其变体,例如长短期记忆网络 (Long Short-Term Memory, LSTM)。 RNN 具有其内部状态,能够更好的处理序列信息,例如句子中前面的单词输入和后面的单词输入是有关系的。但是 RNN 也具有其缺陷,例如当单词数量增加时,那么第一个单词的梯度就可能消失。也就是说,随着RNN读取更多单词,句子开头的单词逐渐变得不那么重要。
Transformer 的处理方式有所不同。它会一次读取所有单词,并权衡每个单词的重要性。因此,更多的注意力集中在更重要的单词上,因此也称为注意力。
而自注意力机制是注意力机制的变体,其减少了对外部信息的依赖,更擅长捕捉数据或特征的内部相关性。自注意力是最新的NLP模型 (例如BERT和GPT-3) 的基石。
计算机视觉中的自注意力
首先简单回顾下卷积神经网络 (Convolutional Neural Networks, CNN) 的要点:CNN 主要由卷积层组成。对于卷积核大小为 3×3 的卷积层,它仅查看输入激活中的 3×3 = 9 个特征(也可以将此区域称为卷积核的感受野)以计算每个输出特征,它并不会查看超出此范围的像素。为了捕获超出此范围的像素,我们可以将核大小略微增加到 5×5 或 7×7,但与特征图大小相比感受野仍然很小。
我们必须增加网络的深度,以使卷积核的感受野足够大以捕获我们想要的内容。与RNN一样,输入特征的相对重要性随着我们在网络层中的移动而下降。因此,我们可以利用自注意力来观察特征图中的每个像素,并注意力集中在更加重要的像素上。
现在,我们将研究自注意力机制的工作原理。自注意力的第一步是将每个输入特征投影到三个向量中,这些向量称为键 (key),查询 (query) 和值 (value),虽然这些术语在计算机视觉中较少出现,但是首先介绍有关这些术语的知识,以便可以更好地理解自注意力,Transformer或NLP有关的文献:
- 值 (value) 表示输入特征。我们不希望自注意力模块查看每个像素,因为这在计算上过于昂贵且不必要。相反,我们对输入激活的局部区域更感兴趣。因此,值在激活图尺寸(例如,它可以被下采样以具有较小的高度和宽度)和通道的数目方面都减小了来自输入特征的维数。 对于卷积层激活,通过使用1x1卷积来减少通道数,并通过最大池化或平均池化来减小空间大小。
- 键和查询 (Keys and queries) 用于计算自注意图中特征的重要性。为了计算位置x x x 处的输出特征,我们在位置x x x 处进行查询,并将其与所有位置处的键进行比较。
为了进一步说明这一点,假设我们有一幅肖像,当网络处理该肖像的一只眼睛时,它首先进行具有语义意义的查询,并使用该肖像的其他区域中的关键字来检查它。如果其他区域中的一个关键是眼睛,那么网络知道它找到了另一只眼睛,这是网络应该关注的区域,以便网络可以进一步处理它。[En]
To further illustrate this point, suppose we have a portrait that, when the network processes one eye of the portrait, it first makes a query that has the semantic meaning of "eye" and checks it using keys in other areas of the portrait. If one of the keys in other areas is the eye, then the network knows that it has found the other eye, which is the area that the network should pay attention to so that the network can process it further.
更一般的,使用数学方程表达:对于特征0 0 0,我们计算向量q 0 × k 0 , q 0 × k 1 , q 0 × k 2 , q 0 × k N − 1 q_0×k_0, q_0×k_1, q_0×k_2, q_0×k_{N-1}q 0 ×k 0 ,q 0 ×k 1 ,q 0 ×k 2 ,q 0 ×k N −1 。然后使用s o f t m a x softmax s o f t m a x 将向量归一化,因此它们的总和为 $1.0,这就是是我们要求的注意力得分。将注意力得分用作权重以执行值的逐元素乘法,以获取注意力输出。
下图说明了如何从查询中生成注意力图:
上图红,最左边一列的图是带有点标记的查询 (queries) 的图像。接下来的五个图像显示了通过查询获得的注意力图。顶部的第一个注意力图查询兔子的一只眼睛;注意图的两只眼睛周围有更多白色区域(指示重要区域),其他区域接近全黑(重要性较低)。
有多种实现自注意力的方法。下图显示了 SAGAN 中的所使用的注意力模块,其中 θ θθ,φ φφ 和 g g g 对应于键,查询和值:
深度学习中的大多数计算都是为了提高速度性能而矢量化的,而对于自注意力也没有什么不同。如果为简单起见忽略 batch 维度,则 1×1 卷积后的激活将具有 (H, W, C) 的形状。第一步是将其重塑为形状为 (H×W, C) 的2D矩阵,并使用 θ θθ 与 φ φφ 的矩阵相乘来计算注意力图。在SAGAN中使用的自注意力模块中,还有另一个1×1卷积,用于将通道数恢复到与输入通道数相同的数量,然后使用可学习的参数进行缩放操作。
; Tensorflow实现自注意力模块
首先在自定义层的build()中定义所有 1×1 卷积层和权重。这里,使用频谱归一化函数作为卷积层的核约束:
class SelfAttention(Layer):
def __init__(self):
super(SelfAttention, self).__init__()
def build(self, input_shape):
n,h,w,c = input_shape
self.n_feats = h * w
self.conv_theta = Conv2D(c//8, 1, padding='same', kernel_constraint=SpectralNorm(), name='Conv_Theta')
self.conv_phi = Conv2D(c//8, 1, padding='same', kernel_constraint=SpectralNorm(), name='Conv_Phi')
self.conv_g = Conv2D(c//8, 1, padding='same', kernel_constraint=SpectralNorm(), name='Conv_g')
self.conv_attn_g = Conv2D(c//8, 1, padding='same', kernel_constraint=SpectralNorm(), name='Conv_AttnG')
self.sigma = self.add_weight(shape=[1], initializer='zeros', trainable=True, name='sigma')
需要注意的是:
- 内部的激活可以减小尺寸,以使计算运行更快。
- 在每个卷积层之后,激活由形状 (H, W, C) 被重塑为形状为 (H*W, C) 的二维矩阵。然后,我们可以在矩阵上使用矩阵乘法。
接下来在 call() 函数中将各层进行连接,用于执行自注意力操作。首先计算 θ \theta θ,φ φφ 和 g g g:
def call(self, x):
n, h, w, c = x.shape
theta = self.conv_theta(x)
theta = tf.reshape(theta, (-1, self.n_feats, theta.shape[-1]))
phi = self.conv_phi(x)
phi = tf.nn.max_pool2d(phi, ksize=2, strides=2, padding='VALID')
phi = tf.reshape(phi, (-1, self.n_feats//4, phi.shape[-1]))
g = self.conv_g(x)
g = tf.nn.max_pool2d(g, ksize=2, strides=2, padding='VALID')
g = tf.reshape(g, (-1, self.n_feats//4, g.shape[-1]))
然后,将按以下方式计算注意力图:
attn = tf.matmul(theta, phi, transpose_b=True)
attn = tf.nn.softmax(attn)
最后,将注意力图与查询 g g g 相乘,并产生最终输出:
attn_g = tf.matmul(attn, g)
attn_g = tf.reshape(attn_g, (-1, h, w, attn_g.shape[-1]))
attn_g = self.conv_attn_g(attn_g)
output = x + self.sigma * attn_g
return output
Original: https://blog.csdn.net/LOVEmy134611/article/details/118894270
Author: 盼小辉丶
Title: TensorFlow实现自注意力机制(Self-attention)

云原生技术持久化存储PV与PVC

tensorboardX详解

tensorflow dataset 用法 from_tensor_slices dataset.repeat dataset.batch dataset.shuffle

基于 Python 的地理空间绘图(附源码)
![[Pytorch系列-55]:循环神经网络 - 使用LSTM网络对股票走势进行预测](https://www.itcode1024.com/wp-content/themes/begin/prune.php?src=https://www.itcode1024.com/wp-content/themes/begin/img/loading.png&w=280&h=210&a=&zc=1)
[Pytorch系列-55]:循环神经网络 – 使用LSTM网络对股票走势进行预测

iOS小技能:队列管理推送通知,解决收款到账并发语音播报问题。

【基音频率】基音matlab基音频率计算【含Matlab源码 1384期】

多传感器融合定位 第九章 基于优化的建图方法

纯跟踪算法用于无人车自动泊车

度量学习和pytorch-metric-learning的使用

FCM公式详细推及代码

图像边缘锯齿及摩尔纹产生的原因

模式识别(3)Kmeans和FCM

tensorflow 实验过程可重复
