zoukankan      html  css  js  c++  java
  • 使用BERT进行情感分类预测及代码实例

    0. BERT介绍

    google 在2018年放出的大杀器, 作为当前NLP的最新技术,此模型在NLP的多个上游下游问题上都取得很好的成绩,刷新记录, 具体原理可以自行google, 这样一个新的技术, 值得我们学习一下, 下面我将给出一个使用BERT进行情感分类预测及代码实例, 供大家分享学习。

    1. BERT配置

    要求配置如下, tensorflow版本不能太低。

    tensorflow >= 1.11.0   # CPU Version of TensorFlow.
    tensorflow-gpu  >= 1.11.0  # GPU version of TensorFlow.
    

    1.1. clone BERT 代码

    首先clone 官方代码,地址如下

    https://github.com/google-research/bert.git
    

    之后我们主要专注于run_classifier.py, 因为这个py文件是BERT的分类任务接口, 接下来我们主要就是对这个文件进行修改, 然后运行即可。 同理 其他任务则运行其他文件,例如问答训练是run_squad.py等

    1.2. 数据处理

    我们一共需要两种数据

    • 数据是BERT开放的预训练模型
    • 我们的数据集

    1.2.1预训练模型

    这是google花费大量资源训练出来的预训练模型, 我的数据集是英文句子, 所以我们使用 BERT-base,uncased
    也就是基础版本+有大小写版本, 当然如果你用中文,google也提供了相应的数据集

    下载地址如下: BERT-Base, Uncased下载地址
    其他的可以在仓库的readme里找到相应的下载地址
    在这里插入图片描述
    然后随便放到一个地方,这里我放到了新建的uncased文件夹里, 路径不一样,模型运行参数会有一点点变化

    1.2.2数据集

    数据集介绍如下:

    这是一个面向句子的情感分类问题。训练集和测试集已给出,使用训练集进行模型训练并对测试集中各句子进行情感预测。训练集包含10026行数据,测试集包含4850行数据。

    训练集

    训练集中,每一行代表一条训练语句,包括四部分内容,使用’ ’分隔符:

    ID1 ID2 polarity text
    

    其中ID1和ID2是爬取句子内容的定位信息,同学们无需使用。text是句子内容,polarity是句子对应情感类型,有positive、negative、neutral三种。

    测试集

    测试集中,每一行代表一条待预测语句,包括四部分内容,使用’ ’分隔符:

    NA line_num unknwn text
    

    以上是我得到的数据集, 但是我们需要从训练集里面挑10%作为开发集

    开发集

    开发集是由训练集得到的,我们使用pandas得到开发集, 代码如下, 开发集和训练集比例为9:1, 两个数据集数据不重合, 我们运行以下代码,得到训练集和开发集, 测试集不用重新划分, 用现成的即可

    data_cut_off.py

    import os
    import pandas as pd
    from sklearn.utils import shuffle
    
    
    if __name__ == '__main__':
        path = "glue/"
        pd_all = pd.read_csv(os.path.join(path, "data.tsv"), sep='	' )
        pd_all = shuffle(pd_all)
    
    
        dev_set = pd_all.iloc[0:int(pd_all.shape[0]/10)]
        train_set = pd_all.iloc[int(pd_all.shape[0]/10): int(pd_all.shape[0])]
        dev_set.to_csv("glue/dev.tsv", index=False, sep='	')
        train_set.to_csv("glue/train.tsv", index=False, sep='	')
    
    

    这样我们就得到我们的数据集合。

    在这里插入图片描述

    2. 修改代码

    因为这次是分类问题, 所以我们需要修改run_classify.py

    2.1 加入新的处理类

    因为我们是做一个分类的任务, 里面自带4个任务的处理类, 其中ColaProcessor是单句分类,和我们的任务较为相近, 所以我们模仿这个类,写一个自己的处理类。

    class EmloProcessor(DataProcessor):
        """Processor for the Emotion data set ."""
    
        def get_train_examples(self, data_dir):
            """定义开发集的数据是什么,data_dir会作为参数传进去, 这里就是加上你的文件名即可 """
            return self._create_examples(
                self._read_tsv(os.path.join(data_dir, "train.tsv"), ), "train")
    
        def get_dev_examples(self, data_dir):
            """定义开发集的数据是什么,data_dir会作为参数传进去,模型训练的时候会用到,这里就是加上你的文件名即可 """
            return self._create_examples(
                self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
    
        def get_test_examples(self, data_dir):
            """定义测试集的数据是什么, 用于预测数据 ,在训练时没有用到这个函数, 这里写预测的数据集"""
            return self._create_examples(
                self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
    
        def get_labels(self):
            """ 这里是显示你一共有几个分类标签, 在此任务中我有3个标签,如实写上  标签值和 csv里面存的值相同 """
            return ["neutral", "positive", "negative"]
    
        def _create_examples(self, lines, set_type):
            """这个函数是用来把数据处理, 把每一个例子分成3个部分,填入到InputExample的3个参数
            text_a 是 第一个句子的文本
            text_b 是 第二个句子的文本 但是由于此任务是单句分类, 所以 这里传入为None
            guid 是一个二元组  第一个表示此数据是什么数据集类型(train dev test) 第二个表示数据标号
            label 表示句子类别
            """
            examples = []
            for (i, line) in enumerate(lines):
    
                guid = "%s-%s" % (set_type, i)
                #print(line, i)
                # 获取text  第三列和第四列分别是 类别  文本 所以分情况添加
                text_a = tokenization.convert_to_unicode(line[3])
                if set_type == "test":
                    #测试集的label 是要预测的 所以我们暂时先随便填一个类别即可 这里我选择都是neutral类
                    label = "neutral"
                else:
                    label = tokenization.convert_to_unicode(line[2])
    
                # 加入样本
                examples.append(
                    InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
            return examples
    
    

    有兴趣的盆友可以看看其他的3个类。

    2.2 处理类注册

    同样我们需要在主函数里把我们的类当做参数选项,给他加个选项, 也就是当参数填emlo时,使用的数据处理类是我们自己写的处理类

    def main(_):
      tf.logging.set_verbosity(tf.logging.INFO)
    
      processors = {
          "cola": ColaProcessor,
          "mnli": MnliProcessor,
          "mrpc": MrpcProcessor,
          "xnli": XnliProcessor,
          "emlo": EmloProcessor
      }
    
    

    3. 运行代码

    运行代码需要提供参数, 这里我建议直接在pycharm编译器里加参数,或者直接命令行运行参数, 而不用按照官方教材 run xxx.sh

    这里我给出我的编译参数, 如果你运行不了, 建议 改小max_seq_length, train_batch_size,

    python
    run_classifier.py
    --task_name=emlo
    --do_train=true
    --do_eval=true
    --data_dir=./glue
    --vocab_file=./uncased/uncased_L-12_H-768_A-12/vocab.txt
    --bert_config_file=./uncased/uncased_L-12_H-768_A-12/bert_config.json
    --init_checkpoint=./uncased/uncased_L-12_H-768_A-12/bert_model.ckpt
    --max_seq_length=128
    --train_batch_size=32
    --learning_rate=2e-5
    --num_train_epochs=3.0
    --output_dir=./tmp/emotion/
    
    • task_name 表示我调用的是什么处理类 ,这里我们是用我们新的类所以选 emlo
    • 文件dir 可以自己定义, 如果无定义到会出错, 我这里是有3个文件夹 uncased里面放预训练模型, glue放数据,tmp/emotion里面放结果

    训练结果如下:
    在这里插入图片描述

    4. 分类预测

    4.1 修改参数, 进行预测

    预测的话, 将运行参数改为以下即可

    python run_classifier.py 
      --task_name=emlo 
      --do_predict=true 
      --data_dir=./glue 
      --vocab_file=./uncased/uncased_L-12_H-768_A-12/vocab.txt 
      --bert_config_file=./uncased/uncased_L-12_H-768_A-12/bert_config.json 
      --init_checkpoint=./tmp/emotion/bert_model.ckpt
      --max_seq_length=128 
      --output_dir=./tmp/emotion_out/
    

    将会返回一个tsv, 每一列表示这一行的样本是这一类的概率
    在这里插入图片描述
    每一类代表的类别和 在run_classify.py里面定义的lab顺序相同
    在这里插入图片描述

    4.2 得到类别

    结果不能是概率,而是类别, 所以我们写一个脚本进行转化
    get_results.py

    import os
    import pandas as pd
    
    
    if __name__ == '__main__':
        path = "tmp/emotion_out/"
        pd_all = pd.read_csv(os.path.join(path, "test_results.tsv") ,sep='	',header=None)
    
        data = pd.DataFrame(columns=['polarity'])
        print(pd_all.shape)
    
        for index in pd_all.index:
            neutral_score = pd_all.loc[index].values[0]
            positive_score = pd_all.loc[index].values[1]
            negative_score = pd_all.loc[index].values[2]
    
            if max(neutral_score, positive_score, negative_score) == neutral_score:
                # data.append(pd.DataFrame([index, "neutral"],columns=['id','polarity']),ignore_index=True)
                data.loc[index+1] = ["neutral"]
            elif max(neutral_score, positive_score, negative_score) == positive_score:
                #data.append(pd.DataFrame([index, "positive"],columns=['id','polarity']),ignore_index=True)
                data.loc[index+1] = [ "positive"]
            else:
                #data.append(pd.DataFrame([index, "negative"],columns=['id','polarity']),ignore_index=True)
                data.loc[index+1] = [ "negative"]
            #print(negative_score, positive_score, negative_score)
    
        data.to_csv(os.path.join(path, "pre_sample.tsv"),sep = '	')
        #print(data)
    

    得到最终预测结果
    在这里插入图片描述

    5. 运行问题

    5.1 出现内存不够

    官方解释影响内存大小的参数
    The factors that affect memory usage are:

    • max_seq_length: The released models were trained with sequence lengths
      up to 512, but you can fine-tune with a shorter max sequence length to save
      substantial memory. This is controlled by the max_seq_length flag in our
      example code.
    • train_batch_size: The memory usage is also directly proportional to
      the batch size.
    • Model type, BERT-Base vs. BERT-Large: The BERT-Large model
      requires significantly more memory than BERT-Base.
    • Optimizer: The default optimizer for BERT is Adam, which requires a lot
      of extra memory to store the m and v vectors. Switching to a more memory
      efficient optimizer can reduce memory usage, but can also affect the
      results. We have not experimented with other optimizers for fine-tuning.

    Using the default training scripts (run_classifier.py and run_squad.py), we
    benchmarked the maximum batch size on single Titan X GPU (12GB RAM) with
    TensorFlow 1.11.0:

    System Seq Length Max Batch Size
    BERT-Base 64 64
    128 32
    256 16
    320 14
    384 12
    512 6
    BERT-Large 64 12
    128 6
    256 2
    320 1
    384 0
    512 0
    • 对于参数max_seq_length, train_batch_size 越小, 内存使用越小
    • 对于使用的预训练集 BERT-Base 使用内存比 BERT-Large小
    • 使用不同的优化器也会造成一定的影响

    作者给出了一些他使用的12g显存的搭配, 可以参考使用

    6. 源码 GITHUB 地址

    特意直接开放源码, 供大家参考

    https://github.com/wangjiwu/BERT-emotion-classification

  • 相关阅读:
    poj3278 Catch That Cow
    poj2251 Dungeon Master
    poj1321 棋盘问题
    poj3083 Children of the Candy Cor
    jvm基础知识—垃圾回收机制
    jvm基础知识1
    java面试基础必备
    java soket通信总结 bio nio aio的区别和总结
    java scoket aIO 通信
    java scoket Blocking 阻塞IO socket通信四
  • 原文地址:https://www.cnblogs.com/qq874455953/p/12458069.html
Copyright © 2011-2022 走看看