前言

开发该课题也有一个月了,整个过程并不是很顺利,很多细节部分如果没有得到及时梳理,对以后的研究和论文写作也有坏处。基于以上和其他原因,遂决定分阶段进行记录。

数据集

深度学习项目的良好开端就是有一个优良标注的数据集。而由于本课题起源于一个极小领域下,导致数据集必须完全自建。所有工作由我一人进行,工作量不可避免的大。所以必须尽可能的减少工作量,尽量实现在课题的中后期的所有标注工作都由程序自动化解决。

计组数据集的构建分为了以下几个过程:

  • 计组数据集来源
  • 数据预处理
  • 数据集的预标注
  • 基于词典的多次迭代标注
  • 数据集格式的转换

接下来对每一个部分进行详述。

计组数据集来源

目前数据的来源如下:

  • 计算机组成原理第6版 (白中英),pdf 转 txt
  • 计算机组成原理第6版 (白中英) 课件,ppt 转 txt

数据预处理

以下是大概的预处理过程:

  1. 将所有的文本合并到一个文件,方便后续操作;
  2. 手工去掉一些与课题无关的文本和小部分错误内容;
  3. 去掉所有的空白字符(空格、换行符、制表符等);
  4. 去掉所有的特殊字符(数字、半角符号、特殊字符);
  5. 以中文句号进行分割,分别以整句、分词的形式输出到 json 文件中。

处理结果:

  • 1
    2
    3
    4
    
    // 整句
    {
      "0": "\u8ba1\u7b97\u673a\u7cfb\u7edf\u4e0d\u540c\u4e8e\u4e00\u822c\u7684\u7535\u5b50\u8bbe\u5907\uff0c\u5b83\u662f\u4e00\u4e2a\u7531\u786c\u4ef6\u3001\u8f6f\u4ef6\u7ec4\u6210\u7684\u590d\u6742\u7684\u81ea\u52a8\u5316\u8bbe\u5907"
    }
    
  • 1
    2
    3
    4
    
    // 分词
    {
      "0": ["\u8ba1", "\u7b97", "\u673a", "\u7cfb", "\u7edf", "\u4e0d", "\u540c", "\u4e8e", "\u4e00", "\u822c", "\u7684", "\u7535", "\u5b50", "\u8bbe", "\u5907", "\uff0c", "\u5b83", "\u662f", "\u4e00", "\u4e2a", "\u7531", "\u786c", "\u4ef6", "\u3001", "\u8f6f", "\u4ef6", "\u7ec4", "\u6210", "\u7684", "\u590d", "\u6742", "\u7684", "\u81ea", "\u52a8", "\u5316", "\u8bbe", "\u5907"]
    }
    

数据集的预标注

以上所有数据处理完后,共得到5632条文本。如果要自己一条条的标注,真就是整一个月啥也别干,所以还是要用比较省力的方式进行标注。我选择用一个在中文语料集上训练过的预训练模型进行第一轮标注,也就是预标注。

我选择了 RaNER命名实体识别-中文-通用领域-large 作为预标注阶段的预训练模型。该模型的标签如下:

实体类型英文名
公司名CORP
创作名CW
其他组织名GRP
地名LOC
人名PER
消费品PROD

为什么要选择这个模型呢?我当时认为有以下几点可以考虑:

  • 标签覆盖范围广:其他的预训练模型只对 PER、LOC、ORG 这三种基本实体有所覆盖,如 CPU、内存这类实体反而识别不出来。相比以上,该模型能成功将计组教材中的大部分实体识别出来,并赋予 PROD、CW、GRP、CORP、PER等标签;
  • 中文平台 ModelScope:因为 ModelScope 在国内,所以各种工具使用起来相对方便。

整个预标注过程如下:

  1. 读取以整句进行分割的语料集;
  2. 构建 Pytorch 的 Dataset 、DataLoader ,方便后续分批加载数据;
  3. 创建 ModelScope 的 Pipeline ;
  4. 将数据顺序输入到 Pipeline 中,由模型进行推理;
  5. 将结果输出到 txt 文件中。
1
2
文本:计算机系统不同于一般的电子设备,它是一个由硬件、软件组成的复杂的自动化设备。
预标注结果:{'output': [{'type': 'PROD', 'start': 0, 'end': 5, 'prob': 0.12411527, 'span': '计算机系统'}]}

可以从上面的结果中看到,计算机系统这个实体被识别了出来,并被标注为 PROD 消费品。但是硬件、软件这两个概念实体没有识别出来,说明预标注的结果只能在一定程度上减少工作量,其余的大部分工作仍需要更高精度的校对。

(标注的结果分析:在所有数据集都处理完成之后才能进行这一步)

基于词典的多次迭代标注

预标注的准确率极为有限,出现了大量识别错漏的情况。这伴随而来的是超大工作量,想要在短时间内修复绝大部分错误几乎是不可能的。那有没有什么方法可以半自动,甚至在之后可以全自动的解决这些问题呢?我想到的是基于词典的多次迭代标注方法。

为了能快速准确的校对大量数据,引入了词典。所谓词典就是 Python 的字典数据结构,由大量键值对组成。为了方便进行迭代标注,我做了以下三个工作:

  • 分割数据集:数据集以训练集 : 验证集 : 测试集 = 8 : 1 : 1 的比例进行划分,而训练集又分成了 5 份;

  • 细分标签:

    • 将计组实体分为了以下十一类:
      LabelMeaningUse
      COMP组件用于标注计算机系统的具体组件,如“寄存器”、“总线”、“控制单元”等
      DATA数据用于标注数据类型和格式,如“二进制数据”、“十六进制数据”等
      ARCH架构用于标注计算机体系结构相关的实体,如冯·诺依曼架构、RISC等
      PROG程序与软件用于标注具体的程序或软件,如“操作系统”、“编译器”等
      PROT网络协议用于标注网络协议或通信协议,如“TCP/IP”、“HTTP”等
      PERF性能指标用于标注与计算机性能相关的实体,如处理速度、吞吐量、延迟、响应时间等
      STOR存储器用于标注各种存储类型和技术,如“RAM”、“ROM”、“闪存”等
      ALG算法用于标注算法相关的实体,如排序算法、加密算法
      IOIO设备用于标注与输入输出设备相关的实体,如键盘、鼠标、显示器、打印机等
      TECH技术用于标注计算机科学技术和概念,如“虚拟内存”、“流水线”、“缓存”等
      INST指令用于标注具体的指令或指令集,如“ADD指令”、“MIPS指令集”等
  • 最长匹配原则:

    • 以“页式虚拟存储系统中,虚地址空间被分成等长的页,称为逻辑页”为例;
    • 地址空间、虚地址空间都被标记为 DATA 实体。在这里标记地址空间为 DATA 不完整的,而遵循最长匹配原则,虚地址空间被标记为 DATA 。

以上部分完成后,才正式开始迭代标注,以下是一个大致过程:

  1. 以第一份数据集的校对结果构建初始词典;
  2. 在其他份数据集校对前先用词典进行一次快速校对;
  3. 每次人工校对完一份数据集,就以其标注结果更新词典;
  4. 重复 1~3 ,直到基于完整数据集的词典更新完毕,得到最终版本词典。

值得一提的是,第一份训练集、验证集、测试集都参与了初始词典的构建,主要采用人工校对。标注平台选用开源库 Open Source Data Labeling | Label Studio 在本地进行标注。

最终版本的词典精确率和召回率都很高,明显高于没有微调的预训练模型。之后还有什么文本,直接用以上方法进行一次快速标注。

数据集格式的转换

模型训练的数据格式有两种:

  • json-tag

    1
    
    {"words": ["痛", "1", "天", "。"], "ner": ["B-SIGNS", "O", "O", "O"]}
    
  • conll

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    当	O
    一	O
    c	B-STOR
    a	I-STOR
    c	I-STOR
    h	I-STOR
    e	I-STOR
    行	E-STOR
    已	O
    授	O
    

把标注过的数据转换为以上格式,就得到用于训练的标准数据集了。