• BERT中文预训练模型:
      • BERT模型整体架构基于Transformer模型架构(只使用Transformer中的编码器), BERT中文预训练模型的Transformer编码器具有12层, 输出层中的线性层具有768个节点, 即输出张量最后一维的维度是768. 它使用的多头注意力机制结构中, 头的数量为12, 模型总参数量为110M. 同时, 它在中文简体和繁体上进行训练, 因此适合中文简体和繁体任务.

    • BERT中文预训练模型作用:
      • 在实际的文本任务处理中, 有些训练语料很难获得, 他们的总体数量和包含的词汇总数都非常少, 不适合用于训练带有Embedding层的模型, 但这些数据中却又蕴含这一些有价值的规律可以被模型挖掘, 在这种情况下,使用预训练模型对原始文本进行编码是非常不错的选择, 因为预训练模型来自大型语料, 能够使得当前文本具有意义, 虽然这些意义可能并不针对某个特定领域, 但是这种缺陷可以使用微调模型来进行弥补.

    • 使用BERT中文预训练模型对两个句子进行编码:
      1. import torch
      2. import torch.nn as nn
      3. # 使用torch.hub加载bert中文模型的字映射器
      4. tokenizer = torch.hub.load('huggingface/pytorch-transformers', 'tokenizer', 'bert-base-chinese')
      5. # 使用torch.hub加载bert中文模型
      6. model = torch.hub.load('huggingface/pytorch-transformers', 'model', 'bert-base-chinese')
      7. def get_bert_encode(text_1, text_2, mark=102, max_len=10):
      8. """
      9. description: 使用bert中文模型对输入的文本对进行编码
      10. :param text_1: 代表输入的第一句话
      11. :param text_2: 代表输入的第二句话
      12. :param mark: 分隔标记, 是预训练模型tokenizer本身的标记符号, 当输入是两个文本时,
      13. 得到的index_tokens会以102进行分隔
      14. :param max_len: 文本的允许最大长度, 也是文本的规范长度即大于该长度要被截断, 小于该长度要进行0补齐
      15. :return 输入文本的bert编码
      16. """
      17. # 使用tokenizer的encode方法对输入的两句文本进行字映射.
      18. indexed_tokens = tokenizer.encode(text_1, text_2)
      19. # 准备对映射后的文本进行规范长度处理即大于该长度要被截断, 小于该长度要进行0补齐
      20. # 所以需要先找到分隔标记的索引位置
      21. k = indexed_tokens.index(mark)
      22. # 首先对第一句话进行长度规范因此将indexed_tokens截取到[:k]判断
      23. if len(indexed_tokens[:k]) >= max_len:
      24. # 如果大于max_len, 则进行截断
      25. indexed_tokens_1 = indexed_tokens[:max_len]
      26. else:
      27. # 否则使用[0]进行补齐, 补齐的0的个数就是max_len-len(indexed_tokens[:k])
      28. indexed_tokens_1 = indexed_tokens[:k] + (max_len-len(indexed_tokens[:k]))*[0]
      29. # 同理下面是对第二句话进行规范长度处理, 因此截取[k:]
      30. if len(indexed_tokens[k:]) >= max_len:
      31. # 如果大于max_len, 则进行截断
      32. indexed_tokens_2 = indexed_tokens[k:k+max_len]
      33. else:
      34. # 否则使用[0]进行补齐, 补齐的0的个数就是max_len-len(indexed_tokens[:k])
      35. indexed_tokens_2 = indexed_tokens[k:] + (max_len-len(indexed_tokens[k:]))*[0]
      36. # 最后将处理后的indexed_tokens_1和indexed_tokens_2再进行相加
      37. indexed_tokens = indexed_tokens_1 + indexed_tokens_2
      38. # 为了让模型在编码时能够更好的区分这两句话, 我们可以使用分隔ids,
      39. # 它是一个与indexed_tokens等长的向量, 0元素的位置代表是第一句话
      40. # 1元素的位置代表是第二句话, 长度都是max_len
      41. segments_ids = [0]*max_len + [1]*max_len
      42. # 将segments_ids和indexed_tokens转换成模型需要的张量形式
      43. segments_tensor = torch.tensor([segments_ids])
      44. tokens_tensor = torch.tensor([indexed_tokens])
      45. # 模型不自动求解梯度
      46. with torch.no_grad():
      47. # 使用bert model进行编码, 传入参数tokens_tensor和segments_tensor得到encoded_layers
      48. encoded_layers, _ = model(tokens_tensor, token_type_ids=segments_tensor)
      49. return encoded_layers

    • 代码位置: /data/doctor_online/bert_serve/bert_chinese_encode.py

    • 输入参数:
      1. text_1 = "人生该如何起头"
      2. text_2 = "改变要如何起手"

    • 调用:
      1. encoded_layers = get_bert_encode(text_1, text_2)
      2. print(encoded_layers)
      3. print(encoded_layers.shape)

    • 输出效果:
      1. tensor([[[ 1.0210, 0.0659, -0.3472, ..., 0.5131, -0.7699, 0.0202],
      2. [-0.1966, 0.2660, 0.3689, ..., -0.0650, -0.2853, -0.1777],
      3. [ 0.9295, -0.3890, -0.1026, ..., 1.3917, 0.4692, -0.0851],
      4. ...,
      5. [ 1.4777, 0.7781, -0.4310, ..., 0.7403, 0.2006, -0.1198],
      6. [ 0.3867, -0.2031, -0.0721, ..., 1.0050, -0.2479, -0.3525],
      7. [ 0.0599, 0.2883, -0.4011, ..., -0.1875, -0.2546, 0.0453]]])
      8. torch.Size([1, 20, 768])

    • 小节总结:
      • 学习了BERT中文预训练模型的有关知识和作用.
      • 使用BERT中文预训练模型对句子编码的函数: get_bert_encode