目标:

在NLP领域,基于公开语料的预训练模型,在专业领域迁移时,会遇到专业领域词汇不在词汇表的问题,本文介绍如何添加专有名词到预训练模型。

例如,在bert预训练模型中,并不包含财经词汇,比如‘市盈率’等财务指标词汇,本文将介绍:

  • 如何把专业名词添加到词汇表中
  • 方法1:修改 vocab
  • 方法2:更通用,修改分词器tokenizer
  • 如何保留现有模型能力,并训练新词汇的embedding表示

内容:

NLP的分词

NLP的处理流程:

  1. 对输入的句子进行分词,得到词语及下标
  2. 通过embedding层获得词语对应的embedding
  3. embedding送入到预训练模型,经过attention注意力机制,获得token在句子中的语义embedding向量
  4. 利用语义embedding向量,构建下游任务。

其中,预训练模型是在公开语料上训练的,我们在做迁移学习,把模型迁移到财经领域时,会面临的一个问题,就是财经词汇不在词汇表,会被拆分成单个字,从而会导致专业名词的完整意思的破坏,或者让模型去学习时,不那么直观,比如:

  • ‘华为的市盈率较高’ 默认会被拆分为:[', ‘’, ‘华为’, ‘的’, ‘市’, ‘盈’, ‘率’, ‘较高’, ‘’]
  • 可见,市盈率被拆分成了 ‘市’, ‘盈’, ‘率’。
  • 我们可以让显式的告诉分词器,市盈率是一个专业名词,无需拆分。因此,经过处理后,词汇被分成了[‘’, ‘’, ‘华为’, ‘的’, ‘市盈率’, ‘’, ‘较高’, ‘’]
  • 达到了预期目标
from transformers import AutoTokenizer,AutoModelPRE_TRAINED_MODEL_NAME='xlm-roberta-base'
tokenizer = AutoTokenizer.from_pretrained(PRE_TRAINED_MODEL_NAME)e = tokenizer.encode('华为的市盈率较高')
s = [tokenizer.decode(i) for i in e]
print(s)
# ['<s>', '', '华为', '的', '市', '盈', '率', '较高', '</s>']
tokenizer.add_tokens(["市盈率"])
e2 = tokenizer.encode('华为的市盈率较高')
s2 = [tokenizer.decode(i) for i in e2]
print(s2)
# ['<s>', '', '华为', '的', '市盈率', '', '较高', '</s>']

实现方式:

有两种实现

    1. 在vocab.txt中,利用前100里的[unused],将[unused]换成自己想要添加的。具体有多少个[unused]要看自己的预训练模型,可能100个,可能1000个,但都有限。如果要添加的词汇量小,并且预训练模型确实有vocab.txt文件,则可以,比如bert,目前看对于领域来说,量不够大。
    1. 更加通用的办法:通过tokenizer,向词汇表中追加新的专业词汇,没有不限。特别是现在比较复杂的模型,都没有单独的vocab.txt文件了,只能通过这种方式。
import torch
from transformers import AutoTokenizer,AutoModelPRE_TRAINED_MODEL_NAME='xlm-roberta-base'
tokenizer = AutoTokenizer.from_pretrained(PRE_TRAINED_MODEL_NAME)
model = AutoModel.from_pretrained(PRE_TRAINED_MODEL_NAME)print(len(tokenizer))  # 250002
tokenizer.add_tokens(["NEW_TOKEN"])
print(len(tokenizer))  # 250003

新词汇embedding的生成:

新词汇的加入,势必会不适配原始embedding的维度,原始的embedding维度为[vocab_size,hidden_size],但是我们又不可能重新去训练整个embedding,我们想尽量保留原始embedding参数,因此,这里比较巧妙的运用了reshape技巧,人为添加新词汇的embedding(随机的,没学习),然后使用领域材料进行学习。
这种方法,因为是添加token,需要修改embedding matrix。
实验证明resize matrix不会打扰原始预训练的embeddings。

import torch
from transformers import AutoTokenizer,AutoModelPRE_TRAINED_MODEL_NAME='xlm-roberta-base'
tokenizer = AutoTokenizer.from_pretrained(PRE_TRAINED_MODEL_NAME)
model = AutoModel.from_pretrained(PRE_TRAINED_MODEL_NAME)print(len(tokenizer))  # 250002
tokenizer.add_tokens(["NEW_TOKEN"])
print(len(tokenizer))  # 250003x = model.embeddings.word_embeddings.weight[-1, :] # 原始最后一个token的embeddingmodel.resize_token_embeddings(len(tokenizer)) # 调整embedding维度
# The new vector is added at the end of the embedding matrixprint(model.embeddings.word_embeddings.weight[-1, :])
# Randomly generated matrix 添加的embedding是随机值。with torch.no_grad():model.embeddings.word_embeddings.weight[-1, :] = torch.zeros([model.config.hidden_size])
# 人为设置新添加的embedding为0print(model.embeddings.word_embeddings.weight[-1, :])
# outputs a vector of zeros of shape [768]y = model.embeddings.word_embeddings.weight[-2, :] # 原始最后一个token变成倒数第二了,取其embeddingprint(x == y) # 原始token的embedding会改变吗?原来embedding weight 不会变e = tokenizer.encode('华为的市盈率较高')
s = [tokenizer.decode(i) for i in e]
print(s)
tokenizer.add_tokens(["市盈率"])
e2 = tokenizer.encode('华为的市盈率较高')
s2 = [tokenizer.decode(i) for i in e2]
print(s2)

有了这个初始embedding,经过MLM等任务,就可以训练新词汇的embedding表示了,通过下游任务来学习这个embedding。

掌握:

  • 添加领域词汇的方式
  • 修改新embedding的方式
  • 训练新token的embedding

Pytorch transformers tokenizer 分词器词汇表添加新的词语和embedding相关推荐

  1. Keras的Tokenizer分词器

    Tokenizer类 keras.preprocessing.text.Tokenizer(num_words=None, filters='!"#$%&()*+,-./:;< ...

  2. jieba 的Tokenizer分词器

    2021SC@SDUSC 一.gen_pfdict函数 在初始化的过程中,会构建前缀词典.构建前缀词典的入口函数是gen_pfdict(self, f),解析离线统计词典文本文件,每一行分别对应着词. ...

  3. oracle无法分区,oracle已存在的表添加新分区的方法

    现在有一张表如下: create table WRITE_USER ( area_code              VARCHAR2(8), user_no                VARCH ...

  4. MySQL数据表添加新字段

    我们不关注约束条件,只添加字段. 在表的最后位置添加新字段(默认) 语法: ALTER TABLE 表名ADD 新字段名 数据类型 约束条件; 在表的开头位置添加新字段 语法: ALTER TABLE ...

  5. ElasticSearch之Tokenizer 分词器

    java学习讨论群:725562382 Tokenizer Standard Tokenizer curl -X POST "192.168.0.120:9200/_analyze" ...

  6. php 添加表,关于php:如何向MYSQL表添加新列

    我正在尝试使用PHP将新列添加到我的MYSQL表中. 我不确定如何更改表以创建新列. 在我的评估表中 assessmentid | q1 | q2 | q3 | q4 | q5 假设我有一个带有文本框 ...

  7. 如何给表添加新的字段

    其实就这样一句代码,alter table [表名]  add [字段名]  字段的数据类型 举个例子: create table UserInfo (      id uniqueidentity  ...

  8. Pytorch:jieba分词、hanlp分词、词性标注、命名实体识别、one-hot、Word2vec(CBOW、skipgram)、Word Embedding词嵌入、fasttext

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 文本预处理及其作用: 文本语料在输送给模型前一般需要一系列的预 ...

  9. ElasticSearch03_Mapping字段映射、常用类型、数据迁移、ik分词器、自定义分词器

    文章目录 ①. Mapping字段映射概述 ②. 常用类型如下 - text.keyword ③. 映射中对时间类型详解 ④. ES的keyword的属性ignore_above ⑤. 映射的查看.创 ...

最新文章

  1. MySQL数据库分组查询group by(having)
  2. 谁说女生不适合当程序员?
  3. 【机器学习实战】第3章 决策树(Decision Tree)
  4. 实战解析:真实AI场景下,极小目标检测与精度提升 | 百度AI公开课
  5. 编译boost时 cmake的debug:math命令无法解析“*”号
  6. Android开发之旅:组件生命周期(二)
  7. 数据库外键的使用原则
  8. [SecureCRT]通过SFTP方式上传本地文件到服务器
  9. 实战:轻量级分布式文件系统FastDFS(GraphicsMagick图片压缩)
  10. passwd命令限制用户密码到期时间
  11. Git 版本控制原理
  12. 使用APP inventor制作蓝牙串口助手【智能浇灌模型中用到】
  13. Iframe背景透明
  14. pscc2018教程photoshop软件全套入门到精通分享
  15. 用数字万用表测量电阻-2/4/6线制测量
  16. 用Python来判断输入的身份证号的性别
  17. 抽屉新热榜html源码,利用scrapy获取抽屉新热榜的标题和内容以及新闻地址保存到本地...
  18. linux中pwd命令,pwd命令
  19. 经典的mac阅读写作学习工具合集
  20. ToolGood.Words一款高性能敏感词(非法词/脏字)检测过滤组件,附带繁体简体互换,支持全角半角互换,汉字转拼音,模糊搜索等功能。

热门文章

  1. 还不清楚视频如何转文字?借助这3款软件可以实现
  2. 为什么创业的人都爱跑步
  3. vuejs-- webpack环境下父子组件的使用
  4. 00-线段检测--FLD
  5. 思考的梯子 | 黄金圈法则What-How-Why(超干货)
  6. 数智企业 财税云领——用友全线产品支持专票电子化
  7. 利用python对Excel进行读写操作
  8. 织梦php模板在哪个文件夹,织梦模板如何修改默认templets模板文件夹名称的方法...
  9. SAP 薪酬计算流程
  10. 仿知音漫画网站源码 PC+手机端 帝国cms7.5内核