dataframe 输出标题_基于feature based的BERT中文标题分类实战

本文介绍了基于feature based的BERT中文标题分类,通过预训练的BERT模型提取文本特征,然后构建简单神经网络进行训练。利用BERT的输出特征进行降维处理,仅取每个样本的第一个字符的隐层状态作为表征。实验显示,尽管模型在训练数据上的loss迅速下降,但仍有优化空间。这种方法在资源有限的情况下,可作为快速构建文本分类模型的途径。
摘要由CSDN通过智能技术生成

11cdb751f6acdbe1c644d38be4be386b.png

基于feature based的BERT中文标题分类实战

在上篇分享中

https://zhuanlan.zhihu.com/p/72448986​zhuanlan.zhihu.com
88884d7b5ee28e5c08e30ee06007e7a0.png

我们实现了基于pytorch pretrained-bert提供的pretrained-bert进行fine tuning的中文标题分类,事实上在pytorch pretrained-bert中对于下游NLP任务的应用提供了比较丰富的封装和实现,如针对文本分类的BertForSequenceClassification,针对字符分类的BertForTokenClassification,以及判断句子前后关系的BertForNextSentencePrediction

事实上,上面提到的这些类都是在原先的BertModel基础上对于各种应用的适配,如在pool层上加一个输出大小为1的dense层做二分类便可以用于BertForSequenceClassificationBertForNextSentencePrediction,而在pool层上加一个输出大小为词典数的dense层便可用于BertForTokenClassification,因此具体代码上大同小异,都非常方便。如果想要观察各个模型具体的网络结构上的差异,可以通过https://zhuanlan.zhihu.com/p/71207696 中提到的可视化工具进行网络的可视化,下面是上文中的标题分类模型的网络结构图。

b0a90fa8bc5244b4625656389d5b6f7e.png

从上图可以看出,因为总共有28个类别,因此会有769 × 28的全连接层,总之通过可视化可以帮助我们更加直观的了解各个网络之间的差异。

在上篇分享中我们侧重的是fine tuning based,本文主要侧重的是feature based,即将bert作为文本语义特征的提取/生成工具,通过为样本生成低维稠密特征而快速适用于多种机器学习、深度学习模型,该种方式或许无法完全发挥bert的表征学习能力,但是为后续模型的选择和设计提供了很大的便捷性及自由度。本文中使用的数据上一篇文章中进行了仔细的介绍,因此有需要的话可以参阅本专栏前一篇文章。

载入库

import csv
import os
import sys
import pickle
import pandas as pd
import numpy as np
from concurrent.futures import ThreadPoolExecutor
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import Conv1d,BatchNorm1d,MaxPool1d,ReLU,Dropout
from torch.optim import Adam
import pickle
from sklearn.preprocessing import LabelEncoder
from torch.optim import optimizer
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler, TensorDataset
from torch.nn import CrossEntropyLoss,BCEWithLogitsLoss
from tqdm import tqdm_notebook, trange
from pytorch_pretrained_bert import BertTokenizer, BertModel, BertForMaskedLM, BertForSequenceClassification
from pytorch_pretrained_bert.optimization import BertAdam, WarmupLinearSchedule
import matplotlib.pyplot as plt
%matplotlib inline

数据预处理

class DataPrecessForSingleSentence(object):
    """
    对文本进行处理
    """
​
    def __init__(self, bert_tokenizer, max_workers=10):
        """
        bert_tokenizer :分词器
        dataset        :包含列名为'text'与'label'的pandas dataframe
        """
        self.bert_tokenizer = bert_tokenizer
        # 创建多线程池
        self.pool = ThreadPoolExecutor(max_workers=max_workers)
        # 获取文本与标签
​
    def get_input(self, dataset, max_seq_len=30):
        """
        通过多线程(因为notebook中多进程使用存在一些问题)的方式对输入文本进行分词、ID化、截断、填充等流程得到最终的可用于模型输入的序列。
        
        入参:
            dataset     : pandas的dataframe格式,包含两列,第一列为文本,第二列为标签。标签取值为{0,1},其中0表示负样本,1代表正样本。
            max_seq_len : 目标序列长度,该值需要预先对文本长度进行分别得到,可以设置为小于等于512(BERT的最长文本序列长度为512)的整数。
        
        出参:
            seq         : 在入参seq的头尾分别拼接了'CLS'与'SEP'符号,如果长度仍小于max_seq_len,则使用0在尾部进行了填充。
            seq_mask    : 只包含0、1且长度等于seq的序列,用于表征seq中的符号是否是有意义的,如果seq序列对应位上为填充符号,
                          那么取值为1,否则为0。
            seq_segment : shape等于seq,因为是单句,所以取值都为0。
            labels      : 标签取值为{0,1},其中0表示负样本,1代表正样本。
        
            
        """
        sentences = dataset.iloc[:, 0].tolist()
        labels = dataset.iloc[:, 1].tolist()
        # 切词
        tokens_seq = list(
            self.pool.map(self.bert_tokenizer.tokenize, sentences))
        # 获取定长序列及其mask
        result = list(
            self.pool.map(self.trunate_and_pad, tokens_seq,
                          [max_seq_len] * len(tokens_seq)))
        seqs = [i[0] for i in result]
        seq_masks = [i[1] for i in result]
        seq_segments = [i[2] for i in result]
        return seqs, seq_masks, seq_segments, labels
​
    def trunate_and_pad(self, seq, m
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值