本文(部分内容)翻译自文章A Visual Guide to Using BERT for the First Time,其作者为Jay Alammar,访问网址为:http://jalammar.github.io/a-visual-guide-to-using-bert-for-the-first-time/ ,可以作为那些不熟悉BERT的读者首次阅读。文章中如有翻译不当之处,还请批评指正。



  本文是关于如何使用BERT的变异版本来进行句子分类的简单教程。该例子足够简单,因此可以作为首次使用BERT的介绍,当然,它也包含了一些关键性的概念。

数据集:SST2

  本文中使用的数据集为SST2,它包含了电影评论的句子,每一句带有一个标签,或者标注为正面情感(取值为1),或者标注为负面情感(取值为0)。

模型:句子情感分类

  我们的目标是创建一个模型,它能够处理一个句子(就行我们数据集中的句子那样)并且输出1(表明该句子具有正面情感)或者0(表明该句子具有负面情感)。我们设想它长这样:



事实上,该模型包含两个模型:

  • DistillBERT会处理句子并把它提取后的信息传递给下一个模型。DistillBERTBERT的变异版本,由HuggingFace小组开发和开源。它是BERT的更轻量、更快速的版本,同时它的表现基本与BERT相近。
  • 下一个模型,从scikit learn中导入的一个基本的逻辑回归模型(Logistic Regression model),它会利用 DistillBERT的处理结果,然后将句子进行分类成正面情感或者负面情感(分别为1或者0)。

在两个模型之间传递的数据为1个768维的向量。我们可以把这个向量理解为这个句子的嵌入向量(Embedding Vector),用于分类。

模型训练

  尽管我们用了两个模型,但是我们只会训练逻辑回归模型。对于DistillBERT,我们会使用已经预训练好的英语模型。该模型,既不会被训练也不会做微调(fine-tuned),直接进行句子分类。这是因为,我们可以从BERT中获得句子分类的能力。这尤其适合BERT输出的第一个位置(跟[CLS]标志相关)。我相信这是由于BERT的第二个训练模型——下一句分类(Next sentence classification)。该模型的目标在于封装句子级别的语料进行训练,并输出第一个位置。transformers库已经提供了DistillBERT的操作,作为其预训练模型版本。

教程总览

  以下是该教程的计划安排。首先我们会使用DistillBERT来产生2000个句子的句子向量。



这一步之后我们不会接触DistillBERT。接下去只是Scikit Learn的操作。我们将数据集分为训练集和测试集。



接下来我们在训练集上使用逻辑回归模型进行训练。

单次预测如何计算

  在我们讲解代码和解释如何训练模型之前,让我们看一下已预训练好的模型如何进行预测。

  我们尝试着预测句子“a visually stunning rumination on love”。第一步是使用BERT tokenizer 将句子划分成tokens。然后加上句子分类的特殊tokens([CLS]在开始位置,[SEP]在句子结尾)。



第三步是通过已预训练好的模型的嵌入表(embedding table)将每一个tokens映射成各自的id。这一步可以参考word embedding,参考阅读文章The Illustrated Word2vec



我们注意到,tokenizer仅需要一行代码就能完成以上步骤。

tokenizer.encode("a visually stunning rumination on love", add_special_tokens=True)

我们的输入句子现在已经处理成DistilBERT可以处理的格式了。

如果你已经读过Illustrated BERT,那么这一步的可视化如下:

DistilBERT处理流程

  DistilBERT处理输入向量的流程类似于BERT。输出是每一个token对应一个向量。每个向量由768个浮点型数字组成。



因为这是一个句子分类任务,故我们忽略其他向量而只取第一个向量(跟[CLS]相关的那个)。这个向量我们会作为逻辑回归模型的输入。



  从这里开始,就是逻辑回归模型的事儿了,它负责将输入的向量进行分类。我们设想一个预测的流程长这样:

代码

  文章中用到的数据集下载网址为:https://github.com/clairett/pytorch-sentiment-classification/raw/master/data/SST2/train.tsv。下载DistillBERT模型文件,网址为:https://www.kaggle.com/abhishek/distilbertbaseuncased

  原文中这部分的代码讲解比较多,我这边忽略过去了,笔者想按自己的思路来处理,因此这部分内容会有调整。完整的思路如下:

  下载数据集和模型文件,与代码放在同一目录下。建立jupyter脚本,先载入必要的模块:



  接着我们利用pandas读取训练集数据,并统计标签值的频数:



  读取DistillBERT模型文件并创建tokenizer:



  通过tokenizer完成句子切分成tokens,并映射到id:



  由于每个句子的长度可能会不同,因此需要对句子进行填充(Padding),保持每个句子的输入维度一致,句子填充的长度为该数据集中句子长度的最大值。



  对句子进行填充后,然后再进行Masking。这是因为如果我们直接将padded传入BERT,这会造成一定的困扰。我们需要创建另一个变量,来告诉模型去mask之前的填充结果。这就是attention_mask的作用:



  我们的输入已经准备完毕,接下来我们尝试着用DistillBERT来获取向量,也就是之前说的第一步。这一步的处理结果会返回last_hidden_states,而我们的分类模型只需要获取[CLS]这个token对应的输出向量。



可视化的操作说明如下图:



  这样,我们就把之前的每一个句子映射成了1个768维的句子向量,然后就利用逻辑回归模型直接进行训练就可以了。



  最后,我们来看一下这个模型在测试集上的效果:

总结

  本文主要介绍了如何利用DistillBERT和已经封装好的transformers模块,结合逻辑回归模型对英文句子进行文本二分类。后续笔者还会研究在中文上的文本分类以及如何进行微调(Fine_tuning)。

  本项目的Gitlab地址为:https://gitlab.com/jclian91/sentence_classify_using_distillBERT_LR,原文章作者的Github地址为https://github.com/jalammar/jalammar.github.io/blob/master/notebooks/bert/A_Visual_Notebook_to_Using_BERT_for_the_First_Time.ipynb

  感谢大家阅读~

NLP(十九)首次使用BERT的可视化指导的更多相关文章

  1. NLP(二十)利用BERT实现文本二分类

      在我们进行事件抽取的时候,我们需要触发词来确定是否属于某个特定的事件类型,比如我们以政治上的出访类事件为例,这类事件往往会出现"访问"这个词语,但是仅仅通过"访问&q ...

  2. WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形

    原文:WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形 说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘> ...

  3. NLP十大里程碑

    NLP十大里程碑 2.1 里程碑一:1985复杂特征集 复杂特征集(complex feature set)又叫做多重属性(multiple features)描写.语言学里,这种描写方法最早出现在语 ...

  4. Web 开发人员和设计师必读文章推荐【系列二十九】

    <Web 前端开发精华文章推荐>2014年第8期(总第29期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  5. Gradle 1.12翻译——第十九章. Gradle 守护进程

    有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...

  6. 第三百五十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)介绍以及安装

    第三百五十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)介绍以及安装 elasticsearch(搜索引擎)介绍 ElasticSearch是一个基于 ...

  7. 无废话ExtJs 入门教程十九[API的使用]

    无废话ExtJs 入门教程十九[API的使用] extjs技术交流,欢迎加群(201926085) 首先解释什么是 API 来自百度百科的官方解释:API(Application Programmin ...

  8. Python之路【第十九章】:Django进阶

    Django路由规则 1.基于正则的URL 在templates目录下创建index.html.detail.html文件 <!DOCTYPE html> <html lang=&q ...

  9. Bootstrap <基础二十九>面板(Panels)

    Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一个盒子中.创建一个基本的面板,只需要向 <div> 元素添加 class .panel 和 class .pa ...

随机推荐

  1. 洛谷$P$4137 $Rmq\ Problem / mex$ 主席树

    正解:主席树 解题报告: 传送门$QwQ$ 本来以为是道入门无脑板子题,,,然后康了眼数据范围发现并没有我想像的那么简单昂$kk$ 这时候看到$n$的范围不大,显然考虑离散化?但是又感觉似乎布星?因为 ...

  2. 洛谷$P3756\ [CQOI2017]$老$C$的方块 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 看到不能出现给定的讨厌的图形,简单来说就,特殊边两侧的方格不能同时再连方格. 所以如果出现,就相当于是四种方案?就分别炸四个格子. 然后冷静分析一波之后发现 ...

  3. acwing 1250. 格子游戏 并查集

    地址 https://www.acwing.com/problem/content/1252/ Alice和Bob玩了一个古老的游戏:首先画一个 n×nn×n 的点阵(下图 n=3n=3 ). 接着, ...

  4. [02]java数据类型和运算符等知识

    00 Java中的注释 为了方便程序的阅读,Java语言允许程序员在程序中写上一些说明性的文字,用来提高程序的可读性,这些文字性的说明就称为注释.注释不会出现在字节码文件中,即Java编译器编译时会跳 ...

  5. JAVA字节码文件之第三篇(访问标识)

    一.Access Flags 访问标志 访问标志信息包括该 Class 文件是类还是接口,是否被定义成 public 或者 abstract , 如果是类,是否被声明成 final. 访问标志表 二. ...

  6. flask 中的 werkzeug Local,LocalStack 和 LocalProxy 技术应用

    什么是 Local wsgi 每次请求,会把过程进行抽离无状态话,过程数据存储在本次请求的全局变量中,使用到了Local. Local 作为每次请求的全局命令空间,属于每次请求的私有 LocalSta ...

  7. Matlab学习过程中的一些小问题

    1.Overload your functions by having variable number of input and output argumernt.Not only can we ov ...

  8. linux修改环境变量的三种方法【转】

    [环境变量配置的三个方法] 如想将一个路径加入到$PATH中,可以像下面这样做:  1. 控制台中,不赞成使用这种方法,因为换个shell,你的设置就无效了,因此这种方法仅仅是临时使用,以后要使用的时 ...

  9. 对Java中可变参数的理解

    说明 可变参数:是DK1.5之后出现的新特性,其实可变参数是0.1.2.3.....个参数的数组 使用前提 当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数 使用格式 修饰符 ...

  10. lldb调试器知多少

    lldb调试器简介   lldb 是一个有着 REPL 的特性和 C++ .Python 插件的开源调试器.lldb调试器的由来是伴随着Xcode的版本升级而来. Xcode4.3之前使用的默认调试器 ...