基于tensorflow2.0+使用bert获取中文词、句向量并进行相似度分析

人工智能175

本文基于 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):

  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的

打印出出看下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()

基于tensorflow2.0+使用bert获取中文词、句向量并进行相似度分析

现在多个句子的张量做一些改动

因为 _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获取中文词、句向量并进行相似度分析



相关阅读

相关文章
CloudCompare——点云滤波 人工智能

CloudCompare——点云滤波

目录 一、低通滤波 * 1.算法原理 2.软件实现 3.结果展示 二、直通滤波 * 1.算法原理及代码实现 2.软件实现 3.结果展示 三、高斯滤波 * 1.算法原理及代码实现 2.软件实现 3.结果...
塑料袋厚度一般几丝 人工智能

塑料袋厚度一般几丝

原文: https://www.yebaike.com/22/1835428.html?ivk_sa=1024320u 一般的塑料袋厚度都是常规的,没有定性。而塑料袋的厚度是看装载商品的重量来衡量的,...
cocos2dx 第六课 游戏声音 人工智能

cocos2dx 第六课 游戏声音

一.音频文件 wav 无损压缩 mp3 有损压缩 压缩率高 wma 微软有损压缩 和mp3差别不大 caff 苹果开发 无压缩格式 aiff 苹果开发 有损压缩格式 mid 专业音频 ogg 完全免费...
RF模型(随机森林模型)详解 人工智能

RF模型(随机森林模型)详解

入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。 目录 一、RF背景——集成学习中的bagging流派 1、集成学习简介 2、bagging流派...
2021/10/23 人工智能

2021/10/23

利用Anaconda里面自带的Spyder实现Tensorflow调用(CPU版本)和OpenCV调用 这次为了完成图像识别的作业,由于图像背景干扰物太多,只能抱着试着看的心态安装Anaconda,A...
背包、队列、栈 人工智能

背包、队列、栈

本节主要是记录对于的背包、队列、和链表的Java实现代码 背包就是一种不支持从中删除元素的数据类型——它的目的就是帮助用例收集元素并迭代遍历所有收集到的元素。 package com.alg.fund...
Unity 科大讯飞离线语音合成 人工智能

Unity 科大讯飞离线语音合成

好久没有更新文章了,今天我们继续更新科大讯飞的语音的文章。 之前在语音合成部分由于在线语音合成的处理时间太长,所以使用了C#自带的语音合成,处理是快了,但是合成的声音特别难听。 所以今天更新一个离先语...