NLP---Bert分词

基于BERT的无监督分词和句法分析

Q:bert分词步骤

1:构建N * N 的相关性矩阵,计算相邻两个字的相关性,低的话(<阈值)就切割。

在这里插入图片描述

2:将A词进行mask计算出A的embedding,然后将AB两个词一起mask,计算出A的embedding,算两个embedding的距离。

3:距离“远” 表示临词的影响比较大。

例子:

1:比如['我是中国人]

2:第一次先mask’我’,然后mask’我是’,计算距离得到“我”的影响D1。

3:然后mask’是’,根据mask’我是’,计算距离得到“是”的影响D2。

4:根据这三个判断‘是’ 是否需要切开。用D1D2的平均距离代表切割前后对两个字影响的大小,小于阈值则切开。

在这里插入图片描述
在这里插入图片描述


Q:bert分词代码(bert4keras)

1:下载BERT模型 及 配置,bert_config.json / bert_model.ckpt / vocab.txt

2:建立分词器 + 建立模型,加载权重

3:文本编码,生成 token_ids, segment_ids

4:根据文本长度,将token_id复制【2 * length - 1】份,以为token首位为‘/’

5:将mask符号位103进行填补

注意技巧:第一行1个103,第二行2个103,第三行1个103…,按列看,基本都是3个103连着。

6:输入batch_token_ids,batch_segment_ids进行预测

7:用欧式距离去计算两个embedding的距离,

先将token_ids 复制 (2 * length - 1) 份。

#! -*- coding: utf-8 -*-
# BERT做无监督分词
# 介绍:https://kexue.fm/archives/7476

import numpy as np
from bert4keras.models import build_transformer_model
from bert4keras.tokenizers import Tokenizer
from bert4keras.snippets import uniout

# 1:下载BERT模型 及 配置
config_path = '/root/kg/bert/chinese_L-12_H-768_A-12/bert_config.json'
checkpoint_path = '/root/kg/bert/chinese_L-12_H-768_A-12/bert_model.ckpt'
dict_path = '/root/kg/bert/chinese_L-12_H-768_A-12/vocab.txt'

# 2: 建立分词器 + 建立模型,加载权重
tokenizer = Tokenizer(dict_path, do_lower_case=True)  # 建立分词器
model = build_transformer_model(config_path, checkpoint_path)  # 建立模型,加载权重

# 3: 文本编码,生成 token_ids, segment_ids
text = u'大肠杆菌是人和许多动物肠道中最主要且数量最多的一种细菌'
token_ids, segment_ids = tokenizer.encode(text)
length = len(token_ids) - 2

# 4: 根据文本长度,将token_id复制【2 * length - 1】份,以为token首位为‘/’
batch_token_ids = np.array([token_ids] * (2 * length - 1))
batch_segment_ids = np.zeros_like(batch_token_ids)


# 5: 将mask符号位103进行填补
for i in range(length):
    if i > 0:
        batch_token_ids[2 * i - 1, i] = tokenizer._token_mask_id
        batch_token_ids[2 * i - 1, i + 1] = tokenizer._token_mask_id
    batch_token_ids[2 * i, i + 1] = tokenizer._token_mask_id


# 6: 输入batch_token_ids,batch_segment_ids进行预测
vectors = model.predict([batch_token_ids, batch_segment_ids])


# 7: 用欧式距离去计算两个embedding的距离,
def dist(x, y):
    """距离函数(默认用欧氏距离)
    可以尝试换用内积或者cos距离,结果差不多。
    """
    return np.sqrt(((x - y)**2).sum())
    
threshold = 8
word_token_ids = [[token_ids[1]]]
for i in range(1, length):
	# “大肠杆菌是人和许多”
	# 比如i=2
	# d1 = vectors[4, 3]与vectors[3, 3]的距离,[4,3]是单独mask“菌”字emb,[3, 3]是mask"杆菌"后菌的emb
    d1 = dist(vectors[2 * i, i + 1], vectors[2 * i - 1, i + 1])
    # d2 = vectors[2, 2]与vectors[3, 2]的距离,[2,2]是单独mask“杆”字emb,[3, 2]是mask"杆菌"后杆的emb
    d2 = dist(vectors[2 * i - 2, i], vectors[2 * i - 1, i])
    # “杆”与“菌”之间平均距离
    d = (d1 + d2) / 2
    if d >= threshold:
    	# 如果距离大,则表明不能分开
        word_token_ids[-1].append(token_ids[i + 1])
    else:
        word_token_ids.append([token_ids[i + 1]])

words = [tokenizer.decode(ids) for ids in word_token_ids]
print(words)
# 结果:[u'大肠杆菌', u'是', u'人和', u'许多', u'动物', u'肠道', u'中最', u'主要', u'且数量', u'最多', u'的', u'一种', u'细菌']

在这里插入图片描述
在这里插入图片描述


bert分词缺点:

1:不太适合长文本,预测时间太慢了,每一个切割都需要预测。

2:阈值不好把握(代码中为8)。

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值