JointBERT代码复现详解【上】

news2024/9/25 9:38:09

BERT for Joint Intent Classification and Slot Filling代码复现【上】

源码链接:JointBERT源码复现(含注释)

一、准备工作

源码架构
在这里插入图片描述

  • data:存放两个基准数据集;
  • model:JointBert模型的实现;
  • data_loader.py:实现数据加载与准备,将文件中的数据转换成Bert模型可读的、能够理解的数据结构;
  • main.py:包括命令行参数设置、设置是否训练、设置是否对训练完成的模型加载与评估;
  • predict.py:结果预测;
  • trainer.py:模型训练与评估;
  • utils.py:一些辅助函数

项目架构

  1. 数据处理;
  2. 模型实现与目标函数;
  3. 训练与评估;
  4. 主程序与参数设置

项目环境

  1. python>=3.6
  2. torch>=1.6.0
  3. transformers==3.0.2
  4. seqeval==0.0.12 (序列标注任务评估的辅助工具)
  5. pytorch-crf==0.7.2(pytorch版本的CRF组件)

数据集下载
在这里插入图片描述

二、数据处理模块

1.数据文件

在这里插入图片描述
ATIS、SNIPS数据集按照训练集train、验证集dev、测试集test进行划分

  1. label文件保存了意图识别的标签;
  2. seq.in文件每行保存一句输入样本;
  3. seq.out文本每行保存样本的槽位标签序列,用空格进行分割

2.收集类别标签

将所有出现的意图标签和槽位标签进行统计

import os
def vocab_process(data_dir):
    '''
    Args:
        data_dir: 数据集所在的路径
    Returns:
        None
    Result:
        intent的label类型写入一个txt文件
        slot的label类型写入一个txt文件
    '''
    # 标签集合输入到如下文件中
    slot_label_vocab = 'slot_label.txt'
    intent_label_vocab = 'intent_label.txt'

    # 找到训练集数据的路径 进行拼接
    train_dir = os.path.join(data_dir, 'train')
    # 收集intent标签
    with open(os.path.join(train_dir, 'label'), 'r', encoding='utf-8') as f_r, open(os.path.join(data_dir, intent_label_vocab), 'w',
                                                                                    encoding='utf-8') as f_w:
        # 新建intent_vocab集合 提取所有出现的intent的label类型
        intent_vocab = set()
        for line in f_r:
            line = line.strip()
            intent_vocab.add(line)
        # 由于数据集已经划分完成,可能会出现验证集中存在而训练集中不存在的标签,以"UNK"来进行标记
        # 当读取到验证集,需要将未见过的intent标签标记为"UNK"
        additional_tokens = ["UNK"]
        for token in additional_tokens:
            f_w.write(token + '\n')
        # 将vocab以字典序进行排列 也可以自定义其他排列方式
        intent_vocab = sorted(list(intent_vocab))
        for intent in intent_vocab:
            f_w.write(intent + '\n')
    # 收集slot槽位标签
    with open(os.path.join(train_dir, 'seq.out'), 'r', encoding='utf-8') as f_r, open(os.path.join(data_dir, slot_label_vocab), 'w',
                                                                                      encoding='utf-8') as f_w:
        # 新建slot_vocab集合 提取所有出现的slot的label类型
        slot_vocab = set()
        # 一个label序列如下: O O O O O B-fromloc.city_name O B-toloc.city_name B-round_trip I-round_trip
        # 按照空格分割得到label序列
        for line in f_r:
            line = line.strip()
            slots = line.split()
            for slot in slots:
                slot_vocab.add(slot) # 放到slot_vocab集合中
        # label是以BIO形式进行标记,先按BIO后面的实体类别字典序排列,再按照BIO顺序排列
        slot_vocab = sorted(list(slot_vocab), key=lambda x: (x[2:], x[:2]))
        # Write additional tokens 写入其他标签
        # "UNK"标签和上面相同,"PAD"表示被填充的部分的label
        additional_tokens = ["PAD", "UNK"]
        for token in additional_tokens:
            f_w.write(token + '\n')

        for slot in slot_vocab:
            f_w.write(slot + '\n')
if __name__ == "__main__":
    vocab_process('atis')
    vocab_process('snips')

生成结果
在这里插入图片描述
在这里插入图片描述

3.数据样本读取为样本实例

自定义输出类,可以控制输出样本的格式-json

class InputExample(object):
    """
    A single training/test example for simple sequence classification. 一个单独的样本实例
    一个样本完全可以用一个dict来表示,但使用InputExample类,作为一个python类,具有一些方便之处
    Args:
        guid: Unique id for the example.
        words: list. The words of the sequence.
        intent_label: (Optional) string. The intent label of the example.
        slot_labels: (Optional) list. The slot labels of the example.
    """

    def __init__(self, guid, words, intent_label=None, slot_labels=None):
        self.guid = guid # 每个样本的独特序号
        self.words = words # 样本的输入序列
        self.intent_label = intent_label # 样本的intent标签
        self.slot_labels = slot_labels # 样本的slot标签序列

    def __repr__(self):
        # 默认为:“类名 + object at + 内存地址” 这样的信息表示这个实例
        # 重写需要输出的信息
        # print(input_example) 时显示
        return str(self.to_json_string())

    def to_dict(self):
        """Serializes this instance to a Python dictionary."""
        # __dict__:
        # 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的
        # 对象实例的__dict__中存储一些self.xxx的东西
        output = copy.deepcopy(self.__dict__)
        return output

    def to_json_string(self):
        """Serializes this instance to a JSON string."""
        return json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n"

数据处理器类

# 数据处理器类
class JointProcessor(object):
    """Processor for the JointBERT data set """
    # JointBert项目的数据处理器
    def __init__(self, args):
        self.args = args # 项目的参数配置
        # 加载处理好的意图标签和槽位标签
        self.intent_labels = get_intent_labels(args)
        self.slot_labels = get_slot_labels(args)
        # 每个数据集的文件夹中数据格式一致,文件名格式也一致
        self.input_text_file = 'seq.in'
        self.intent_label_file = 'label'
        self.slot_labels_file = 'seq.out'

    # 执行读取文件的函数
    @classmethod
    def _read_file(cls, input_file, quotechar=None):
        """Reads a tab separated value file."""
        # 以行为单位进行读取
        with open(input_file, "r", encoding="utf-8") as f:
            lines = []
            for line in f:
                lines.append(line.strip())
            return lines
    # 对每一个样本进行处理
    def _create_examples(self, texts, intents, slots, set_type):
        """
        Creates examples for the training and dev sets.
        Args:
            texts: list. Sequence of unsplitted texts.需要处理的文本组成的列表
            intents: list. Sequence of intent labels. 意图label组成的列表
            slots: list. Sequence of unsplitted slot labels. 槽位label组成的列表
            set_type: str. train\ dev\ test 训练集、验证集、测试集
        """

        examples = []
        for i, (text, intent, slot) in enumerate(zip(texts, intents, slots)):
            guid = "%s-%s" % (set_type, i)
            # 1. input_text
            words = text.split()  # Some are spaced twice
            # 2. intent
            # 如果验证集或测试集中的标签不在训练集中,将其标为UNK
            intent_label = self.intent_labels.index(intent) if intent in self.intent_labels else self.intent_labels.index("UNK")
            # 3. slot
            slot_labels = []
            for s in slot.split():
                # 如果验证集或测试集中的标签不在训练集中,将其标为UNK
                slot_labels.append(self.slot_labels.index(s) if s in self.slot_labels else self.slot_labels.index("UNK"))
            # 进行验证 防止由于标签遗漏导致的错误
            assert len(words) == len(slot_labels)
            examples.append(InputExample(guid=guid, words=words, intent_label=intent_label, slot_labels=slot_labels))
        return examples

    # get_examples的唯一参数是mode
    def get_examples(self, mode):
        """
        Args:
            mode: train, dev, test
            判断输入的是 训练集、验证集还是测试集,按照对应的路径读取文件
        """
        data_path = os.path.join(self.args.data_dir, self.args.task, mode)
        logger.info("LOOKING AT {}".format(data_path))
        return self._create_examples(texts=self._read_file(os.path.join(data_path, self.input_text_file)),
                                     intents=self._read_file(os.path.join(data_path, self.intent_label_file)),
                                     slots=self._read_file(os.path.join(data_path, self.slot_labels_file)),
                                     set_type=mode)
class Args() :
    task = None
    data_dir = None
    intent_label_file = None
    slot_label_file = None

args = Args()
args.task = 'atis'
args.data_dir = './data'
args.intent_label_file = 'intent_label.txt'
args.slot_label_file = 'slot_label.txt'
# 实例化
processor = JointProcessor(args)
# processor属性
print(processor.intent_labels)
print(processor.slot_labels)
# 读取train样本
train_examples = processor.get_examples('train')
print(len(train_examples))
print(train_examples[5])

在这里插入图片描述

4.将数据处理成Bert能够理解的特征

def convert_examples_to_features(examples, # 输入的训练样本
                                 max_seq_len, # 样本最大长度
                                 tokenizer, # subword tokenizer
                                 pad_token_label_id=-100, # 新加入的标签编号
                                 cls_token_segment_id=0,
                                 pad_token_segment_id=0,
                                 sequence_a_segment_id=0,
                                 mask_padding_with_zero=True):
    '''
    将之前读取的数据进行添加[CLS][SEP]标记,padding操作
    Args:
        examples: 样本实例列表
        max_seq_len: 最大长度
        tokenizer:
        pad_token_label_id:
        cls_token_segment_id: 取0
        pad_token_segment_id: 取0
        sequence_a_segment_id: 取0
        mask_padding_with_zero: attention mask
    Returns:
    '''
    # Setting based on the current model type
    cls_token = tokenizer.cls_token # [CLS]
    sep_token = tokenizer.sep_token # [SEP]
    unk_token = tokenizer.unk_token # [UNK]
    pad_token_id = tokenizer.pad_token_id # [PAD]编号为0

    features = []
    for (ex_index, example) in enumerate(examples):
        if ex_index % 5000 == 0:
            logger.info("Writing example %d of %d" % (ex_index, len(examples)))

        # Tokenize word by word (for NER)
        # bert采用的tokenizer可能会把一个单词分成多个subword,将第一个subword标记为slot label,其他标记为pad label
        tokens = []
        slot_labels_ids = []
        for word, slot_label in zip(example.words, example.slot_labels):
            word_tokens = tokenizer.tokenize(word)
            if not word_tokens:
                word_tokens = [unk_token]  # For handling the bad-encoded word 不能识别的word标记为UNK
            '''
            {
                '0' : 0,
                'B-ENT' : 1 ,
                'I-ENT' : 2
            }
            '''
            # 例如 principle:prin cip le
            # B-ENT:B-ENT,X,X: 1,-100,-100 新添标签 X 新的label类 (最常见)
            # B-ENT:B-ENT,I-ENT,I-ENT: 1,2,2 实体未结束的label类 I-ENT
            # B-ENT:B-ENT,0,0: 1,0,0 非实体 0
            # B-ENT:B-ENT,B-ENT,B-ENT,: 1,1,1 实体的开头部分

            tokens.extend(word_tokens)
            # Use the real label id for the first token of the word, and padding ids for the remaining tokens
            slot_labels_ids.extend([int(slot_label)] + [pad_token_label_id] * (len(word_tokens) - 1))

        # Account for [CLS] and [SEP]
        special_tokens_count = 2
        # 若句子太长将其截断
        # 为保证 tokens 和 slot_labels 两者长度一致,需要对slot_labels做相同操作
        if len(tokens) > max_seq_len - special_tokens_count:
            tokens = tokens[:(max_seq_len - special_tokens_count)]
            slot_labels_ids = slot_labels_ids[:(max_seq_len - special_tokens_count)]

        # Add [SEP] token
        tokens += [sep_token]
        slot_labels_ids += [pad_token_label_id]
        token_type_ids = [sequence_a_segment_id] * len(tokens)

        # Add [CLS] token
        tokens = [cls_token] + tokens
        slot_labels_ids = [pad_token_label_id] + slot_labels_ids
        token_type_ids = [cls_token_segment_id] + token_type_ids

        # 将单词转化为ids
        input_ids = tokenizer.convert_tokens_to_ids(tokens)

        # The mask has 1 for real tokens and 0 for padding tokens. Only real
        # tokens are attended to.
        attention_mask = [1 if mask_padding_with_zero else 0] * len(input_ids)

        # Zero-pad up to the sequence length.
        padding_length = max_seq_len - len(input_ids)
        input_ids = input_ids + ([pad_token_id] * padding_length)
        attention_mask = attention_mask + ([0 if mask_padding_with_zero else 1] * padding_length)
        token_type_ids = token_type_ids + ([pad_token_segment_id] * padding_length)
        slot_labels_ids = slot_labels_ids + ([pad_token_label_id] * padding_length)

        assert len(input_ids) == max_seq_len, "Error with input length {} vs {}".format(len(input_ids), max_seq_len)
        assert len(attention_mask) == max_seq_len, "Error with attention mask length {} vs {}".format(len(attention_mask), max_seq_len)
        assert len(token_type_ids) == max_seq_len, "Error with token type length {} vs {}".format(len(token_type_ids), max_seq_len)
        assert len(slot_labels_ids) == max_seq_len, "Error with slot labels length {} vs {}".format(len(slot_labels_ids), max_seq_len)

        intent_label_id = int(example.intent_label)

        if ex_index < 105:
            print("*** Example ***")
            print("guid: %s" % example.guid)
            print("tokens: %s" % " ".join([str(x) for x in tokens]))
            print("input_ids: %s" % " ".join([str(x) for x in input_ids]))
            print("attention_mask: %s" % " ".join([str(x) for x in attention_mask]))
            print("token_type_ids: %s" % " ".join([str(x) for x in token_type_ids]))
            print("intent_label: %s (id = %d)" % (example.intent_label, intent_label_id))
            print("slot_labels: %s" % " ".join([str(x) for x in slot_labels_ids]))

        features.append(
            InputFeatures(input_ids=input_ids,
                          attention_mask=attention_mask,
                          token_type_ids=token_type_ids,
                          intent_label_id=intent_label_id,
                          slot_labels_ids=slot_labels_ids
                          ))

    return features
def load_and_cache_examples(args, tokenizer, mode):
    processor = processors[args.task](args)

    # Load data features from cache or dataset file
    cached_features_file = os.path.join(
        args.data_dir,
        'cached_{}_{}_{}_{}'.format(
            mode,
            args.task,
            list(filter(None, args.model_name_or_path.split("/"))).pop(),
            args.max_seq_len
        )
    )
    print(cached_features_file)
    if os.path.exists(cached_features_file) and False:
        logger.info("Loading features from cached file %s", cached_features_file)
        features = torch.load(cached_features_file)

    else:
        # Load data features from dataset file
        logger.info("Creating features from dataset file at %s", args.data_dir)
        if mode == "train":
            examples = processor.get_examples("train")
        elif mode == "dev":
            examples = processor.get_examples("dev")
        elif mode == "test":
            examples = processor.get_examples("test")
        else:
            raise Exception("For mode, Only train, dev, test is available")

        # Use cross entropy ignore index as padding label id so that only real label ids contribute to the loss later
        pad_token_label_id = args.ignore_index

        features = convert_examples_to_features(examples, args.max_seq_len, tokenizer,
                                                pad_token_label_id=pad_token_label_id)
        logger.info("Saving features into cached file %s", cached_features_file)
        torch.save(features, cached_features_file)

    # Convert to Tensors and build dataset
    all_input_ids = torch.tensor([f.input_ids for f in features], dtype=torch.long)
    all_attention_mask = torch.tensor([f.attention_mask for f in features], dtype=torch.long)
    all_token_type_ids = torch.tensor([f.token_type_ids for f in features], dtype=torch.long)
    all_intent_label_ids = torch.tensor([f.intent_label_id for f in features], dtype=torch.long)
    all_slot_labels_ids = torch.tensor([f.slot_labels_ids for f in features], dtype=torch.long)

    dataset = TensorDataset(all_input_ids, all_attention_mask,
                            all_token_type_ids, all_intent_label_ids, all_slot_labels_ids)
    return dataset
class Args() :
    task = None
    data_dir = None
    intent_label_file = None
    slot_label_file = None

args = Args()
args.task = 'atis'
args.data_dir = './data'
args.intent_label_file = 'intent_label.txt'
args.slot_label_file = 'slot_label.txt'

args.max_seq_len = 50
args.model_type = 'bert'
args.model_dir = 'experiments/jointbert_0'
args.model_name_or_path = utils.MODEL_PATH_MAP[args.model_type]
args.ignore_index = -100
# 计算交叉熵时,自动忽略标签值
args.train_batch_size = 4
tokenizer = utils.load_tokenizer(args)
load_and_cache_examples(args,tokenizer,mode='train')

在这里插入图片描述

三、模型构建与损失函数

  1. JointBERT模型 ①分类层、②CRF层
  2. 损失函数计算

1.JointBERT模型

导包 原版Bert模型

import torch.nn as nn
from transformers.models.bert.modeling_bert import BertPreTrainedModel, BertModel, BertConfig

from torchcrf import CRF # pip install pytorch-crf
from .module import IntentClassifier, SlotClassifier

两个分类任务各自的MLP全连接层

# intent分类的MLP全连接层
class IntentClassifier(nn.Module):
    def __init__(self, input_dim, num_intent_labels, dropout_rate=0.):
        super(IntentClassifier, self).__init__()
        self.dropout = nn.Dropout(dropout_rate)
        self.linear = nn.Linear(input_dim, num_intent_labels)

    def forward(self, x):
    	# x:[batch_size,input_dim] 维度
        x = self.dropout(x)
        return self.linear(x)
# slot分类的MLP全连接层
class SlotClassifier(nn.Module):
    def __init__(self, input_dim, num_slot_labels, dropout_rate=0.):
        super(SlotClassifier, self).__init__()
        self.dropout = nn.Dropout(dropout_rate)
        self.linear = nn.Linear(input_dim, num_slot_labels)

    def forward(self, x):
    # x:[batch_size,max_seq_len,input_dim]维度
        x = self.dropout(x)
        return self.linear(x)

主模型架构

class JointBERT(BertPreTrainedModel):
    def __init__(self, config, args, intent_label_lst, slot_label_lst):
        super(JointBERT, self).__init__(config)
        self.args = args
        self.num_intent_labels = len(intent_label_lst)
        self.num_slot_labels = len(slot_label_lst)
        self.bert = BertModel(config=config)  # Load pretrained bert
        # 初始化两个分类器
        self.intent_classifier = IntentClassifier(config.hidden_size, self.num_intent_labels, args.dropout_rate)
        self.slot_classifier = SlotClassifier(config.hidden_size, self.num_slot_labels, args.dropout_rate)
        # 是否要用CRF
        if args.use_crf:
            self.crf = CRF(num_tags=self.num_slot_labels, batch_first=True)

    def forward(self, input_ids, attention_mask, token_type_ids, intent_label_ids, slot_labels_ids):
        outputs = self.bert(input_ids, attention_mask=attention_mask,
                            token_type_ids=token_type_ids)  # sequence_output, pooled_output, (hidden_states), (attentions)
        sequence_output = outputs[0] # [bsz,seq_len,hidden_dim]
        pooled_output = outputs[1]  # [CLS]上的输出 BertPooler module,MLP,tanh
        # 初始化分类器
        intent_logits = self.intent_classifier(pooled_output)
        slot_logits = self.slot_classifier(sequence_output)

        # 损失函数
        total_loss = 0
        # 1. Intent Softmax
        if intent_label_ids is not None:
            if self.num_intent_labels == 1:
                intent_loss_fct = nn.MSELoss()
                intent_loss = intent_loss_fct(intent_logits.view(-1), intent_label_ids.view(-1))
            else:
                intent_loss_fct = nn.CrossEntropyLoss()
                intent_loss = intent_loss_fct(intent_logits.view(-1, self.num_intent_labels), intent_label_ids.view(-1))
            total_loss += intent_loss

        # 2. Slot Softmax 采用CRF计算损失函数与交叉熵有一定的区别,需要分类讨论
        if slot_labels_ids is not None:
            if self.args.use_crf:
                slot_loss = self.crf(slot_logits, slot_labels_ids, mask=attention_mask.byte(), reduction='mean')
                slot_loss = -1 * slot_loss  # negative log-likelihood
            else:
                # 指定ignore_index
                slot_loss_fct = nn.CrossEntropyLoss(ignore_index=self.args.ignore_index)
                # Only keep active parts of the loss
                # 只计算非padding部分得loss
                if attention_mask is not None:
                    active_loss = attention_mask.view(-1) == 1 # [B*L,1]
                    print('active_loss:',active_loss)

                    active_logits = slot_logits.view(-1, self.num_slot_labels)[active_loss]
                    print('active_logits:', active_logits)

                    active_labels = slot_labels_ids.view(-1)[active_loss] # [-1,1]
                    print('active_labels:', active_labels)

                    slot_loss = slot_loss_fct(active_logits, active_labels)
                else:
                    slot_loss = slot_loss_fct(slot_logits.view(-1, self.num_slot_labels), slot_labels_ids.view(-1))
            total_loss += self.args.slot_loss_coef * slot_loss

        outputs = ((intent_logits, slot_logits),) + outputs[2:]  # add hidden states and attention if they are here

        outputs = (total_loss,) + outputs

        return outputs  # (loss), logits, (hidden_states), (attentions) # Logits is a tuple of intent and slot logits

在这里插入图片描述
不使用CRF计算损失函数

class Args() :
    task = None
    data_dir = None
    intent_label_file = None
    slot_label_file = None

args = Args()
args.task = 'atis'
args.data_dir = './data'
args.intent_label_file = 'intent_label.txt'
args.slot_label_file = 'slot_label.txt'


args.max_seq_len = 50
args.model_type = 'bert'
args.model_dir = 'experiments/jointbert_0'
args.model_name_or_path = utils.MODEL_PATH_MAP[args.model_type]
args.ignore_index = -100
# 计算交叉熵时,自动忽略标签值
args.train_batch_size = 4
args.dropout_rate = 0.1
args.use_crf = False
args.slot_loss_coef = 1.0

tokenizer = utils.load_tokenizer(args)
config = utils.MODEL_CLASSES[args.model_type][0].from_pretrained(args.model_name_or_path)
intent_label_lst = get_intent_labels(args)
slot_label_lst = get_slot_labels(args)
num_intent_labels = len(intent_label_lst)
num_slot_labels = len(slot_label_lst)

model = utils.JointBERT(config,args,intent_label_lst,slot_label_lst)

# load dataset
train_dataset = load_and_cache_examples(args,tokenizer,mode='train')
# torch自带的
train_sampler = RandomSampler(train_dataset)
train_dataloader = DataLoader(train_dataset, sampler=train_sampler, batch_size=args.train_batch_size)
device = 'cpu'

for step, batch in enumerate(train_dataloader):
    batch = tuple(t.to(device) for t in batch)  # GPU or CPU

    inputs = {'input_ids': batch[0],
              'attention_mask': batch[1],
              'token_type_ids': batch[2],
              'intent_label_ids': batch[3],
              'slot_labels_ids': batch[4]}
    input_ids = inputs['input_ids'] # [B,L]
    attention_mask = inputs['attention_mask'] # [B,L]
    token_type_ids = inputs['token_type_ids'] # [B,L]
    intent_label_ids = inputs['intent_label_ids'] # [B,L]
    slot_label_ids = inputs['slot_labels_ids'] # [B,L]

    if step > 1:
        break
    print('input_ids:',input_ids.shape)
    print('slot_labels_ids',slot_label_ids.shape)
    print('slot_labels_ids', slot_label_ids)

    outputs = model.bert(input_ids,attention_mask=attention_mask,token_type_ids = token_type_ids)
    sequence_output = outputs[0]
    print('sequence_output:',sequence_output.shape)
    pooled_output = outputs[1]
    print('pooled_output:', pooled_output.shape)

    # 计算intent分类的损失
    intent_logits = model.intent_classifier(pooled_output) # [B,22]
    print('intent_logits:',intent_logits.shape)

    intent_loss_fct = nn.CrossEntropyLoss()
    intent_loss = intent_loss_fct(intent_logits.view(-1,num_intent_labels),intent_label_ids.view(-1))

    """
        采用JointBert模型,计算active loss 只计算句子中的非padding部分的损失
    """
    slot_logits = model.slot_classifier(sequence_output)
    print('slot_logits:',slot_logits.shape)

    active_loss = attention_mask.view(-1) == 1
    print('active_loss:',active_loss.shape)

    active_logits = slot_logits.view(-1,num_slot_labels)[active_loss]
    print('slot_logits:',slot_logits.shape)
    print('active_logits:',active_logits.shape)

    active_labels = slot_label_ids.view(-1)[active_loss]
    print('active_labels:',active_labels.shape)

    slot_loss_fct = nn.CrossEntropyLoss()
    slot_loss = slot_loss_fct(active_logits,active_labels)
    print('slot_loss:',slot_loss)

    """
        直接计算 : 利用ignore_index
    """
    slot_loss_fct = nn.CrossEntropyLoss(ignore_index=args.ignore_index)
    slot_loss = slot_loss_fct(
        slot_logits.view(-1,num_slot_labels),
        slot_label_ids.view(-1)
    )
    print('slot_loss:',slot_loss)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
采用CRF计算损失函数

args.use_crf = True
    if step > 0:
        break
    outputs = model.bert(input_ids,attention_mask=attention_mask,token_type_ids = token_type_ids)
    sequence_output = outputs[0]
    slot_logits = model.slot_classifier(sequence_output)
    slot_loss = model.crf(slot_logits,slot_label_ids,mask=attention_mask.byte(),reduction='mean')
    slot_loss = -1 * slot_loss # negative log-likehood
    print('slot_loss:',slot_loss)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/340463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

修改本地host文件加入可用ip使谷歌浏览器翻译插件重新生效

修改本地host文件加入可用ip使谷歌浏览器翻译插件重新生效 第一步&#xff1a;找到host文件&#xff1a; 可以使用这个工具进行对Hosts文件进行一个查找 鼠标放到对应路径上面 点击鼠标右键&#xff0c;选择打开路径就到对应 路径了 也可以复制到这个路径下面去找hosts文件 …

【Node.js实战】一文带你开发博客项目之Koa2重构(实现session、开发路由、联调、日志)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

Redis集群搭建(主从、哨兵、分片)

1.单机安装Redis 首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tcl然后将课前资料提供的Redis安装包上传到虚拟机的任意目录&#xff1a; 例如&#xff0c;我放到了/tmp目录&#xff1a; 解压缩&#xff1a; tar -xzf redis-6.2.4.tar.gz解压后&#xff1…

C# Lambda表达式含义及各种写法

Lambda表达式在各个语言中的表达方式都不太相同&#xff0c;本文重点介绍C#的Lambda表达式。 首先&#xff0c;Lambda表达式就是一个匿名的方法/函数。 以下面的一个完整版作为例子&#xff0c;前面是参数&#xff0c;后面是返回值&#xff1a; 由于 Lambda表达式和委托常常一起…

AI推理计算框架中的内存优化

背景 内存管理是AI计算中非常重要的一部分。我们希望模型计算时占用内存尽可能小&#xff0c;这样我们训练或推理时就可以用更大的batch size使其尽快收敛&#xff0c;或者提高吞吐率。又或者让我们可以使用参数更多、或更复杂的模型从而达到更好的准确率。由于现代深度学习模…

【MySQL数据库】主从复制原理和应用

主从复制和读写分离1. 主从复制的原理2. 主从复制的环境配置2.1 准备好数据库服务器2.2 配置master2.3 配置slave2.4 测试3. 主从复制的应用——读写分离3.1 读写分离的背景3.2 Sharding-JDBC介绍3.3 Sharding-JDBC使用步骤1. 主从复制的原理 MySQL主从复制是一个异步的过程&a…

微服务 RocketMQ-延时消息 消息过滤 管控台搜索问题

~~微服务 RocketMQ-延时消息 消息过滤 管控台搜索问题~~ RocketMQ-延时消息实现延时消息RocketMQ-消息过滤Tag标签过滤SQL标签过滤管控台搜索问题RocketMQ-延时消息 给消息设置延时时间&#xff0c;到一定时间&#xff0c;消费者才能消费的到&#xff0c;中间件内部通过每秒钟扫…

TCP的运输连接管理

TCP的运输连接管理 文章目录TCP的运输连接管理TCP报文格式简介首部各个字段的含义控制位(flags)TCP的连接建立抓包验证一些细节及解答TCP连接释放抓包验证一些细节及解答参考TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放时每一次面向连接的通信…

第一部分:简单句——第一章:简单句的核心——二、简单句的核心变化(主语/宾语/表语的变化)

二、简单句的核心变化 简单句的核心变化其实就是 一主一谓&#xff08;n. v.&#xff09; 表达一件事情&#xff0c;谓语动词是其中最重要的部分&#xff0c;谓语动词的变化主要有四种&#xff1a;三态加一否&#xff08;时态、语态、情态、否定&#xff09;&#xff0c;其中…

MSI_MSI-X中断之源码分析

MSI_MSI-X中断之源码分析 文章目录MSI_MSI-X中断之源码分析一、 怎么发出MSI/MSI-X中断1.1 在RK3399上体验1.1.1 安装工具1.1.2 查看设备MSI-X信息1.1.3 验证MSI-X信息二、 怎么使用MSI/MSI-X三、 MSI/MSI-X中断源码分析3.1 IRQ Domain创建流程3.1.1 GIC3.1.2 ITS3.1.3 PCI MSI…

Linux C/C++ timeout命令实现(运行具有时间限制)

Linux附带了大量命令&#xff0c;每个命令都是唯一的&#xff0c;并在特定情况下使用。Linux timeout命令的一个属性是时间限制。可以为任何命令设置时间限制。如果时间到期&#xff0c;命令将停止执行。 如何使用timeout命令 我们将解释如何使用Linux timeout命令 timeout […

七、Git远程仓库操作——团队成员内协作

1. github远程协作的两种方式 前面我写的笔记&#xff0c;都是自己一个人在玩&#xff0c;无论是本地操作还是推送到远程都是自己推送到自己的仓库。 如果是别人拥有这个仓库&#xff0c;而我想对这个仓库的内容更改后&#xff0c;然后想推送更新到这个仓库&#xff0c;我们要…

【随笔】我迟到的2022年度总结:突破零粉丝,1个月涨粉1000+,2023年目标3万+

前言 我是21年12月注册的csdn&#xff0c; 作为用户平时看看文章&#xff0c;从未参与过写文章这件事。 但这一年的时间我见证了很多新号的崛起&#xff0c;有的号我平时关注比较多&#xff0c;看着他们从零粉丝突破了三万甚至五万的粉丝量。 在csdn上遇到了我的贵人&#x…

位运算 | 1356. 根据数字二进制下 1 的数目排序

LeetCode 1356. 根据数字二进制下 1 的数目排序 给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。如果存在多个数字二进制中 1 的数目相同&#xff0c;则必须将它们按照数值大小升序排列。 文章讲解https://www.programmercarl.com/1356.%…

【微电网】基于风光储能和需求响应的微电网日前经济调度(Python代码实现)

目录 1 概述 2 知识点及数学模型 3 算例实现 3.1算例介绍 3.2风光参与的模型求解 3.3 风光和储能参与的模型求解 3.5 风光储能和需求响应都参与模型求解 3.6 结果分析对比 4 Python代码及算例数据 1 概述 近年来&#xff0c;微电网、清洁能源等已成为全球关注的热点…

Linux Vim编辑器基础讲解

目录 vim三个模式 命令模式 输入模式&#xff08;insert 插入模式、编辑模式&#xff09; 末行模式 编辑简单文档 什么是vim Vim是文本编辑器&#xff0c;是Linux上最常用的文本编辑器 Vim可以建立、编辑、显示文件 绝大多数Linux都会携带vim或者vi vim编辑器和vi编辑器的…

windbg-应用层实时调试

调试符号windbg使用一个或多个目录来存放符号条件&#xff0c;并使用环境变量_NT_SYMBOL_PATH来指向这些环境变量的位置&#xff0c;对操作系统内部模块的符号文件&#xff0c;一般用http://msdl.microsoft.com/download/symbols配置如下&#xff1a;SRV*C:\Symbols*http://msd…

手把手教你部署ruoyi前后端分离版本

下载源码&#xff08;当前版本3.8.5&#xff09;RuoYi-Vue: &#x1f389; 基于SpringBoot&#xff0c;Spring Security&#xff0c;JWT&#xff0c;Vue & Element 的前后端分离权限管理系统&#xff0c;同时提供了 Vue3 的版本 (gitee.com)创建数据库(一定要是这三个&…

【STM32】【HAL库】遥控关灯3 遥控器

相关连接 【STM32】【HAL库】遥控关灯0 概述 【STM32】【HAL库】遥控关灯1主机 【STM32】【HAL库】遥控关灯2 分机 【STM32】【HAL库】遥控关灯3 遥控器 需求 硬件遥控器 控制一个灯的开关(2个按键),发射RF433或红外 使用纽扣电池供电 一键启动,低待机功耗 硬件设计 一键…

推荐系统开源工具RecBole学习

文章全文首发&#xff1a;码农的科研笔记&#xff08;公众号&#xff09; RecBole是由AI Box团队开发的基于Pytorch的推荐系统算法库。该框架从数据处理、模型开发和算法训练都有涉及&#xff0c;能方便进行算法构建和实验对比。 数据组织形式 RecBole约定了一个统一、易用的数…