bert简单介绍和实践

2023-11-08

bert模型是Google在2018年10月发布的语言表示模型,在NLP领域横扫了11项任务的最优结果,可以说是现今最近NLP中最重要的突破。Bert模型的全称是Bidirectional Encoder Representations from Transformers,是通过训练Masked Language Model和预测下一句任务得到的模型。

bert作为预训练模型有两种用法:提取包含上下文意义的向量,对特定任务做微调

同GPT采用两阶段模式:利用双向transformer语言模型进行预训练,通过fine-tuning模式解决下游任务。(它和gpt的区别就是gpt,更适用于文本生成,通过前文去预测当前的字

BERT创新: Masked语言模型和Next Sentence Prediction。

BERT详解https://plmsmile.github.io/2018/12/15/52-bert/

https://blog.csdn.net/weixin_42001089/article/details/97657149

实践

一、安装环境

安装Anaconda,打开Anaconda prompt
创建python=3.7版本的环境,取名叫py36
conda create -n DP python=3.7

激活环境
conda activate DP (conda4之前的版本是:source activate py36 )

退出环境
conda deactivate

下载如下包:
xlwd,xlrd 1.2.0
transformers 4.1.1
pytorch 1.6
numpy 1.19.4
pandas 1.1.4
pytorch 1.6.0+cu101

torch可在官网下载https://pytorch.org/

安装pycharm,新建项目时选择创建的环境(用anaconda 的工具切换环境需要下载包,网络可能不通)

二、token代码

文本转成词向量、 编码、解码功能代码实现
vacab.txt是字典,每行一个字符

import torch
# 自定义token
class Token(object):
    def __init__(self, vocab_file_path, max_len=510):#512-2
        self.vocab_file_path = vocab_file_path
        self.max_len = max_len
        self.word2id, self.id2word = self._load_vovab_file()  # 得到词典
        # 进行参数验证
        if self.max_len > 510:  # 表示超过了bert限定长度512
            raise Exception(print('设置序列最大长度超过bert限制长度,建议设置max_len<=510'))

    # 加载词表生成word2id和id2word列表
    def _load_vovab_file(self):
        with open(self.vocab_file_path, 'r', encoding='utf-8') as fp:
            vocab_list = [i.replace('\n', '') for i in fp.readlines()]
            word2id = {}
            id2word = {}
            for index, i in enumerate(vocab_list):
                word2id[i] = index
                id2word[index] = i
        return word2id, id2word

    # 定义数据编码encode并生成pytorch所需的数据格式
    def encode_str(self, txt_list: list):
        # 针对所有的输入数据进行编码
        return_txt_id_list = []
        return_segment_id_list = []
        return_mask_id_list = []
        for txt in txt_list:
            inner_str = txt
            # 进行判断数据是否超过最大长度
            if len(txt) > self.max_len:
                inner_str = inner_str[:self.max_len]  # 截取
            inner_str_list = list(inner_str)
            # 开始构建各种索引
            inner_seq_list = [self.word2id.get('[CLS]')]
            inner_segment_list = [0] * (self.max_len + 2)  # 构建segment
            inner_mask_list = [1] * (len(inner_str_list) + 2) + \
                              [0] * (self.max_len - len(inner_str_list))  # 计算mask
            for char in inner_str_list:
                char_index = self.word2id.get(char, False)
                if char_index == False:  # 表示该字符串不认识
                    inner_seq_list.append(self.word2id.get('[UNK]')) #开头
                else:
                    inner_seq_list.append(char_index)
            inner_seq_list.append(self.word2id.get('[SEP]'))  # 跟上结尾token
            # 执行padding操作
            if len(inner_seq_list) < 512:
                inner_seq_list += [self.word2id.get('[PAD]')] * (self.max_len - len(inner_str_list))
            return_txt_id_list.append(inner_seq_list)
            #类似[[101, 100, 131, 120, 100, 167, 162, 150, 157, 156, 148, 151, 154, 147, 120, 158, 160, 157, 152, 147, 145, 162, 120, 100, 100, 120, 162, 147, 161, 162, 119, 162, 166, 162, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
            return_segment_id_list.append(inner_segment_list)
            return_mask_id_list.append(inner_mask_list)
        # 构建成为pytorch的数据返回结构
        return_data = {
            'input_ids': torch.tensor(return_txt_id_list),# 就是一连串 token 在字典中的对应id。形状为 (batch_size, sequence_length)
            'token_type_ids': torch.tensor(return_segment_id_list),#就是 token 对应的句子id,值为0或1(0表示对应的token属于第一句,1表示属于第二句)。形状为(batch_size, sequence_length)。
            'attention_mask': torch.tensor(return_mask_id_list)#各元素的值为 0 或 1 ,避免在 padding 的 token 上计算 attention(1不进行masked,0则masked)。形状为(batch_size, sequence_length)。
        }
        return return_data
    # 定义解码操作
    def decode_str(self, index_list):
        return ''.join([self.id2word.get(i) for i in index_list])

三、案例

原理

什么是BERT

词嵌入模型
在这里插入图片描述

优势在这里插入图片描述

bert 与gpt模型原型

在这里插入图片描述

BERT输入表示详解和输出

每个输入有三个embedding,词的Embedding(字向量),Segment的Embedding(文本向量),position的Embedding(位置向量)。

词的Embedding:句子开头有一个特殊的Token [CLS],句子结束有一个特殊的Token [SEP]。如果是两个句子同时输入,则只有开头有[CLS],后面那个句子没有[CLS],只有[SEP]。

Segment的Embedding:为了将多个句子区分,第一个句子可能用0表示,第二个用1,只有一个句子的时候可能只用0,第一个token [CLS]很有用,在进行self-attention时,会获取下文所有信息(编码整个句子的语义)。

position的Embedding:保证序列的顺序性。由于出现在文本不同位置的字/词所携带的语义信息存在差异,因此,BERT模型对不同位置的字/词分别附加一个不同的向量以作区分。有两种。Position Embeddings layer 实际上就是一个大小为 (512, 768) 的lookup表,在BERT中,每个词会被转换成768维的向量表示。第一行是代表第一个序列的第一个位置,第二行代表序列的第二个位置,以此类推。因此,如果有这样两个句子“Hello world” 和“Hi there”, “Hello” 和“Hi”会由完全相同的position embeddings,因为他们都是句子的第一个词。同理,“world” 和“there”也会有相同的position embedding。

在这里插入图片描述
注意这里的分词会把”playing”分成”play”和”##ing”两个Token,这种把词分成更细粒度的Word Piece的方法是一种解决未登录词的常见办法

模型输出则是输入各字对应的融合全文语义信息后的向量表示

BERT预训练

Masked语言模型

在预训练的时候,随机mask掉15%的单词,让语言模型去预测这个单词。
在这里插入图片描述
在这里插入图片描述
问题1:
大量mask标记,造成预训练和finetune时候的差距,因为finetune没有mask,finetune的时候用的是自己的数据集收敛很慢,但是效果好(比单向语言模型慢)

解决方案:
在这里插入图片描述
BERT并不知道[MASK]替换的是哪一个词,而且任何一个词都有可能是被替换掉的,比如它看到的词可能是被替换的词。这样强迫模型在编码当前时刻的时候不能太依赖于当前的词,而要考虑它的上下文,甚至更加上下文进行”纠错”。

Next Sentence Prediction

从文本语料库中随机选择50%正确语句对和50%错误语句对进行训练,与Masked LM任务相结合,让模型能够更准确地刻画语句乃至篇章层面的语义信息。对于像QA、NLI等需要理解多个句子之间关系的下游任务,只靠语言模型是不够的。还需要提前学习到句子之间的关系。是一个二分类任务。输入是A和B两个句子,标记是IsNext或NotNext,用来判断B是否是A后面的句子。这样,就能从大规模预料中学习到一些句间关系。

在这里插入图片描述

模型结构

每层encoder由一个feed forward ,一个multi-head attention, 以及两层layerNorm构成
在这里插入图片描述

在这里插入图片描述

自注意力机制self attention

Transformer是组成BERT的核心模块,而Attention机制又是Transformer中最关键的部分,因此,下面我们从Attention机制开始,介绍如何利用Attention机制构建Transformer模块,在此基础上,用多层Transformer组装BERT模型。

Attention机制的中文名叫“注意力机制”,顾名思义,它的主要作用是让神经网络把“注意力”放在一部分输入上,即:区分输入的不同部分对输出的影响。

Attention机制主要涉及到三个概念:Query、Key和Value。在增强字的语义表示应用场景中,目标字及其上下文的字都有各自的原始Value,Attention机制将目标字作为Query、其上下文的各个字作为Key,并将Query与各个Key的相似性作为权重,把上下文各个字的Value融入目标字的原始Value中.

如下图所示,Attention机制将目标字和上下文各个字的语义向量表示作为输入,首先通过线性变换获得目标字的Query向量表示、上下文各个字的Key向量表示以及目标字与上下文各个字的原始Value表示,然后计算Query向量与各个Key向量的相似度作为权重,加权融合目标字的Value向量和各个上下文字的Value向量,作为Attention的输出,即:目标字的增强语义向量表示
在这里插入图片描述

计算每个token词向量和别的词向量的某种权重关系
在这里插入图片描述
Self-Attention:对于输入文本,我们需要对其中的每个字分别增强语义向量表示,因此,我们分别将每个字作为Query,加权融合文本中所有字的语义信息,得到各个字的增强语义向量,如下图所示。在这种情况下,Query、Key和Value的向量表示均来自于同一输入文本,因此,该Attention机制也叫Self-Attention。
在这里插入图片描述

multi-headed attention
为了增强Attention的多样性,文章作者进一步利用不同的Self-Attention模块获得文本中每个字在不同语义空间下的增强语义向量,并将每个字的多个增强语义向量进行线性组合,从而获得一个最终的与原始字向量长度相同的增强语义向量,如下图所示
在这里插入图片描述

Feed Forward

在这里插入图片描述
在这里插入图片描述

应用

预训练模型、文本分类、命名实体识别、机器翻译,问答系统,文本摘要、知识图谱、聊天机器人等

  • 预训练模型

在这里插入图片描述

  • 文本分类
    在这里插入图片描述

在这里插入图片描述

单句子分类(CLS+句子):
输入是一个序列,所有的Token都是属于同一个Segment(Id=0),我们用第一个特殊Token [CLS]的最后一层输出接上softmax进行分类,用分类的数据来进行Fine-Tuning。利用CLS进行分类。

多句子分类(CLS+句子A+SEP+句子B):
对于相似度计算等输入为两个序列的任务,过程如图左上所示。两个序列的Token对应不同的Segment(Id=0/1)。我们也是用第一个特殊Token [CLS]的最后一层输出接上softmax进行分类,然后用分类数据进行Fine-Tuning。利用CLS分类。

NER(CLS+句子):序列标注,比如命名实体识别,输入是一个句子(Token序列),除了[CLS]和[SEP]的每个时刻都会有输出的Tag,然后用输出的Tag来进行Fine-Tuning利用句子单词做标记。QA:CLS+问题+SEP+文章。比较麻烦,比如比如SQuAD v1.1数据集,输入是一个问题和一段很长的包含答案的文字(Paragraph),输出在这段文字里找到问题的答案。

  • 命名实体识别
    在这里插入图片描述

使用预训练模型实践

预测词语

from transformers import pipeline
unmasker = pipeline('fill-mask', model='bert-base-uncased')
unmasker("Hello I'm a [MASK] model.")

在这里插入图片描述
获取文本的特征

from transformers import BertTokenizer, BertModel
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained("bert-base-uncased")
text = "Replace me by any text you'd like."
encoded_input = tokenizer(text, return_tensors='pt')
output = model(**encoded_input)

模型存在一定偏见

from transformers import pipeline
unmasker = pipeline('fill-mask', model='bert-base-uncased')
unmasker("The man worked as a [MASK].")


unmasker("The woman worked as a [MASK].")

在这里插入图片描述

scratch实践-文本分类

参考https://zhuanlan.zhihu.com/p/72448986

import os
import sys
import pickle
import pandas as pd
import numpy as np
from concurrent.futures import ThreadPoolExecutor
import torch
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
from sklearn.metrics import precision_recall_curve,classification_report
import matplotlib.pyplot as plt
# 加载数据
data = pd.read_table('data/dev.tsv')
data = data.iloc[:,[3,1]]
# 列名重新命名
data.columns = ['text','label']
# 标签编码
# 因为label为中文格式,为了适应模型的输入需要进行ID化,此处调用sklearn中的label encoder方法快速进行变换。

le = LabelEncoder()
le.fit(data.label.tolist())
data['label'] = le.transform(data.label.tolist())
# 分词工具
bert_tokenizer = BertTokenizer.from_pretrained('bert-base-chinese', do_lower_case=False)


# 封装类
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, max_seq_len):
        """
        1. 因为本类处理的是单句序列,按照BERT中的序列处理方式,需要在输入序列头尾分别拼接特殊字符'CLS'与'SEP',
           因此不包含两个特殊字符的序列长度应该小于等于max_seq_len-2,如果序列长度大于该值需要那么进行截断。
        2. 对输入的序列 最终形成['CLS',seq,'SEP']的序列,该序列的长度如果小于max_seq_len,那么使用0进行填充。

        入参:
            seq         : 输入序列,在本处其为单个句子。
            max_seq_len : 拼接'CLS'与'SEP'这两个特殊字符后的序列长度

        出参:
            seq         : 在入参seq的头尾分别拼接了'CLS'与'SEP'符号,如果长度仍小于max_seq_len,则使用0在尾部进行了填充。
            seq_mask    : 只包含0、1且长度等于seq的序列,用于表征seq中的符号是否是有意义的,如果seq序列对应位上为填充符号,
                          那么取值为1,否则为0。
            seq_segment : shape等于seq,因为是单句,所以取值都为0。

        """
        # 对超长序列进行截断
        if len(seq) > (max_seq_len - 2):
            seq = seq[0:(max_seq_len - 2)]
        # 分别在首尾拼接特殊符号
        seq = ['[CLS]'] + seq + ['[SEP]']
        # ID化
        seq = self.bert_tokenizer.convert_tokens_to_ids(seq)
        # 根据max_seq_len与seq的长度产生填充序列
        padding = [0] * (max_seq_len - len(seq))
        # 创建seq_mask
        seq_mask = [1] * len(seq) + padding
        # 创建seq_segment
        seq_segment = [0] * len(seq) + padding
        # 对seq拼接填充序列
        seq += padding
        assert len(seq) == max_seq_len
        assert len(seq_mask) == max_seq_len
        assert len(seq_segment) == max_seq_len
        return seq, seq_mask, seq_segment

# 类初始化
processor = DataPrecessForSingleSentence(bert_tokenizer= bert_tokenizer)
# 产生输入ju 数据
seqs, seq_masks, seq_segments, labels = processor.get_input(
    dataset=data, max_seq_len=30)

# 加载预训练的bert模型
# model = BertForSequenceClassification.from_pretrained('C:\Users\LENOVO\Desktop\AI_\bert-base-chinese', num_labels=28)
model = BertForSequenceClassification.from_pretrained(r'C:\Users\LENOVO\Desktop\AI_\bert-base-chinese', num_labels=2)
#数据格式化
# 转换为torch tensor
t_seqs = torch.tensor(seqs, dtype=torch.long)
t_seq_masks = torch.tensor(seq_masks, dtype = torch.long)
t_seq_segments = torch.tensor(seq_segments, dtype = torch.long)
t_labels = torch.tensor(labels, dtype = torch.long)

train_data = TensorDataset(t_seqs, t_seq_masks, t_seq_segments, t_labels)
train_sampler = RandomSampler(train_data)
train_dataloder = DataLoader(dataset= train_data, sampler= train_sampler,batch_size = 256)

# 将模型转换为trin mode
model.train()
# 待优化的参数
param_optimizer = list(model.named_parameters())
no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight']

optimizer_grouped_parameters = [
    {
        'params':
        [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)],
        'weight_decay':
        0.01
    },
    {
        'params':
        [p for n, p in param_optimizer if any(nd in n for nd in no_decay)],
        'weight_decay':
        0.0
    }
]
optimizer = BertAdam(optimizer_grouped_parameters,
                     lr=2e-05,
                     warmup= 0.1 ,
                     t_total= 2000)

device = 'cpu'

## 存储每一个batch的loss
loss_collect = []
for i in trange(10, desc='Epoch'):
    for step, batch_data in enumerate(
            tqdm_notebook(train_dataloder, desc='Iteration')):
        batch_data = tuple(t.to(device) for t in batch_data)
        batch_seqs, batch_seq_masks, batch_seq_segments, batch_labels = batch_data
        # 对标签进行onehot编码
        one_hot = torch.zeros(batch_labels.size(0), 2).long()
        one_hot_batch_labels = one_hot.scatter_(
            dim=1,
            index=torch.unsqueeze(batch_labels, dim=1),
            src=torch.ones(batch_labels.size(0), 2).long())

        logits = model(
            batch_seqs, batch_seq_masks, batch_seq_segments, labels=None)
        logits = logits.softmax(dim=1)
        loss_function = CrossEntropyLoss()
        loss = loss_function(logits, batch_labels)
        loss.backward()
        loss_collect.append(loss.item())
        print("\r%f" % loss, end='')
        optimizer.step()
        optimizer.zero_grad()
plt.figure(figsize=(12,8))
plt.plot(range(len(loss_collect)), loss_collect,'g.')
plt.grid(True)
plt.show()

#验证集合
torch.save(model,open("fine_tuned_chinese_bert.bin","wb"))
#加载测试数据
test_data = pd.read_table('data/dev.tsv')
test_data = data.iloc[:,[3,1]]
test_data.columns = ['text','label']


# test_data = pd.read_pickle("title_category_valid.pkl")
# test_data.columns = ['text','label']
# 标签ID化
test_data['label'] = le.transform(test_data.label.tolist())
# 转换为tensor
test_seqs, test_seq_masks, test_seq_segments, test_labels = processor.get_input(
    dataset=test_data, max_seq_len=30)
test_seqs = torch.tensor(test_seqs, dtype=torch.long)
test_seq_masks = torch.tensor(test_seq_masks, dtype = torch.long)
test_seq_segments = torch.tensor(test_seq_segments, dtype = torch.long)
test_labels = torch.tensor(test_labels, dtype = torch.long)
test_data = TensorDataset(test_seqs, test_seq_masks, test_seq_segments, test_labels)
test_dataloder = DataLoader(dataset= train_data, batch_size = 256)
# 用于存储预测标签与真实标签
true_labels = []
pred_labels = []
model.eval()
# 预测
with torch.no_grad():
    for batch_data in tqdm_notebook(test_dataloder, desc = 'TEST'):
        batch_data = tuple(t.to(device) for t in batch_data)
        batch_seqs, batch_seq_masks, batch_seq_segments, batch_labels = batch_data
        logits = model(
            batch_seqs, batch_seq_masks, batch_seq_segments, labels=None)
        logits = logits.softmax(dim=1).argmax(dim = 1)
        pred_labels.append(logits.detach().numpy())
        true_labels.append(batch_labels.detach().numpy())
# 查看各个类别的准召
print(classification_report(np.concatenate(true_labels), np.concatenate(pred_labels)))

参考:
腾讯视频bert模型深度修炼指南
词向量详解:从word2vec、glove、ELMo到BERT
Bert输入输出是什么

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

bert简单介绍和实践 的相关文章

随机推荐

  • MySQL WHERE语句筛选操作符

    使用SELECT语句但不使用WHERE子句在表中查询数据 则会获取表中的所有行记录 这些行记录中大部分是不想要的行记录 WHERE子句允许根据指定的过滤表达式或条件来指定要选择的行 1 等于 等于 几乎任何数据类型都可以使用它 2 lt g
  • 小程序坑录-wx.getLocation接口申请

    最近在用uni app通用框架做h5和小程序 结果在小程序审核的时候 又遇到了很多天坑 故记录之 从2022 年 7 月 14 日开始 使用位置接口 就必须在app json中进行声明了 除此之外 在正式使用时 还需要在开发管理 接口权限内
  • 期货开户关于基本面量化

    一 库存 供求矛盾看库存 东西没有了 缺了 就会涨价 不缺 一般不会涨 所以 一定要注意库存 去库存快的品种 特别是库存低 价格低的品种 要重点关注 库存有一点要特别注意 要是 有效去库存 通过降价让下游买货 这种 去库存 不是根本 因为库
  • Leetcode:链表刷题(7道经典题目)

    Leetcode 链表刷题 7道经典题目 本文带来的是以链表为主题的一些经典题目 203 移除链表元素 707 设计链表 206 反转链表 24 两两交换链表中的节点 19 删除链表的倒数第 N 个结点 面试题 02 07 链表相交 142
  • Redis设置失效时间

    Redis设置失效时间还有nx和nxx 通过设置失效时间 可以将到达规定时间对应的key和value进行删除 设置失效时间的两种方式 1 在设值的时候设置失效时间 set code test ex px 秒 毫秒 时间 数值 set cod
  • 深度学习 FairMOT多目标跟踪(PANDA)

    FairMOT 复赛期间对于多目标跟踪任务使用的baseline 本质属于联合学习检测和嵌入模型 Joint Detection and Embedding JDE 毕设项目演示地址 链接 毕业项目设计代做项目方向涵盖 目标检测 语义分割
  • 关于航模的几点积累(四)关于螺旋桨

    关于固定翼飞行器的螺旋桨 1 螺旋桨的几种类型 按材质 塑料 木质 碳纤维 玻璃纤维 尼龙等 按桨叶数量 单叶桨 双叶桨 三叶桨等 按固定方式 快拆桨 大孔桨 适配子弹头 小孔桨 适配螺旋桨保护器 这几种螺旋桨之间的对比分析 2 螺旋桨的重
  • 计算机软件工程操作系统期末复习题

    1 计算机操作系统的功能是 D A 把源程序代码转换为目标代码 B 实现计算机用户之间的相互交流 C 完成计算机硬件与软件之间的转换 D 控制 管理计算机系统的资源和程序的执行 在现代计算机系统中 用户用高级语言编写的源程序必须通过编译程序
  • Elasticsearch Head的使用

    目录 概述 一 安装 Elasticsearch Head 二 解压文件 三 安装Elasticsearch Head依赖 四 启动 Elasticsearch Head 五 修改Elasticsearch Head启动端口号 六 使用 E
  • STM32的PWM控制4个舵机

    本人虽然接触STM32快半年了 但是最近才开始系统的学习STM32 建议一边学 一边做东西 能够更快的提升自己 我用的定时器是TIM3 所以我会把我出现的问题 分享给大家 希望大佬多多指教 因为我先进行部分映射 但是控制某个舵机的PB4引脚
  • 【SVN内网穿透】远程访问Linux SVN服务

    文章目录 前言 1 Ubuntu安装SVN服务 2 修改配置文件 2 1 修改svnserve conf文件 2 2 修改passwd文件 2 3 修改authz文件 3 启动svn服务 4 内网穿透 4 1 安装cpolar内网穿透 4
  • 【微信公众号对接】有关签名一直报错,提示invalid signature问题(我的签名和使用微信开发者工具验证返回的签名的是一致的)但还是报错!!!

    今天对接公众号 一直提示我签名有问题 但是我的签名和官方生成的签名一致 下面是对应数据比对 我的签名 微信官方提供签名 经过比对 两者是一致的 但是 就是一直提示错误 后面是解决思路 1 首先是需要在公众号管理平台配置对应服务器信息 包含白
  • 软件测试大作业 题目 网站测试,[软件分析与测试大作业] 测试性分析软件

    软件分析与测试 考试大作业 1 假设某单位内部电话号码由三部分组成 分别是 分机号 前缀 后缀 其中 分机号为空白或一位数字 前缀为非 0 开头的二位数字 后缀为非全0的3位数字 假定被测程序能接受一切符合上述规定的电话号码 拒绝所有不符合
  • 2023牛客暑期多校训练营7 I-We Love Strings (分块)

    文章目录 题目大意 题解 参考代码 题目大意 题解 这题给定的 n n n 大小和 s i s i si 的总长度有玄机
  • transformers学习笔记3

    创建model的方法 automodel创建预训练模型 使用automodel直接创建 使用的是hug face官网上的预训练好的模型参数 完成创建后再使用自己本地的数据集进行迁移训练 automodel api 去官网上下载用户指定类型模
  • com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

    com mysql cj jdbc exceptions CommunicationsException Communications link failure 这个问题就是本地sql没有开始 详情请看点击此处
  • 华为机试-称砝码

    文章目录 描述 输入描述 输出描述 代码解析 描述 现有n种砝码 重量互不相等 分别为 m1 m2 m3 mn 每种砝码对应的数量为 x1 x2 x3 xn 现在要用这些砝码去称物体的重量 放在同一侧 问能称出多少种不同的重量 注 称重重量
  • 地平线 AI 芯片工具链 - 03 自定义模型转换

    地平线 AI 芯片工具链 03 自定义模型转换 1 前提条件 2 文件目录 3 模型可视化 4 模型校验 5 模型编译 1 前提条件 地平线 AI 芯片工具链 01 配置安装 待转换模型 onnx 模型 其他类型可转为 onnx 模型 2
  • springboot项目如何开启热部署

    1 添加依赖
  • bert简单介绍和实践

    bert模型是Google在2018年10月发布的语言表示模型 在NLP领域横扫了11项任务的最优结果 可以说是现今最近NLP中最重要的突破 Bert模型的全称是Bidirectional Encoder Representations f