JointBERT代码复现详解【下】

news2024/9/24 11:29:21

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

链接直达:JointBERT代码复现详解【上】

四、模型训练与评估

Trainer

  • training:梯度更新
  • evaluate:评估序列标注任务如何得到预测结果、评估函数

1.初始化准备

    def __init__(self, args, train_dataset=None, dev_dataset=None, test_dataset=None):
        self.args = args
        self.train_dataset = train_dataset
        self.dev_dataset = dev_dataset
        self.test_dataset = test_dataset

        self.intent_label_lst = get_intent_labels(args)
        self.slot_label_lst = get_slot_labels(args)
        # Use cross entropy ignore index as padding label id so that only real label ids contribute to the loss later
        self.pad_token_label_id = args.ignore_index

        self.config_class, self.model_class, _ = MODEL_CLASSES[args.model_type]
        self.config = self.config_class.from_pretrained(args.model_name_or_path, finetuning_task=args.task)
        self.model = self.model_class.from_pretrained(args.model_name_or_path,
                                                      config=self.config,
                                                      args=args,
                                                      intent_label_lst=self.intent_label_lst,
                                                      slot_label_lst=self.slot_label_lst)

        # GPU or CPU
        self.device = "cuda" if torch.cuda.is_available() and not args.no_cuda else "cpu"
        self.model.to(self.device)

2.模型训练

    def train(self):
        train_sampler = RandomSampler(self.train_dataset)
        train_dataloader = DataLoader(self.train_dataset, sampler=train_sampler, batch_size=self.args.train_batch_size)

        if self.args.max_steps > 0:
            t_total = self.args.max_steps
            self.args.num_train_epochs = self.args.max_steps // (len(train_dataloader) // self.args.gradient_accumulation_steps) + 1
        else:
            t_total = len(train_dataloader) // self.args.gradient_accumulation_steps * self.args.num_train_epochs

        # Prepare optimizer and schedule (linear warmup and decay)
        no_decay = ['bias', 'LayerNorm.weight']
        optimizer_grouped_parameters = [
            {'params': [p for n, p in self.model.named_parameters() if not any(nd in n for nd in no_decay)],
             'weight_decay': self.args.weight_decay},
            {'params': [p for n, p in self.model.named_parameters() if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
        ]
        optimizer = AdamW(optimizer_grouped_parameters, lr=self.args.learning_rate, eps=self.args.adam_epsilon)
        scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=self.args.warmup_steps, num_training_steps=t_total)

        # Train!
        logger.info("***** Running training *****")
        logger.info("  Num examples = %d", len(self.train_dataset))
        logger.info("  Num Epochs = %d", self.args.num_train_epochs)
        logger.info("  Total train batch size = %d", self.args.train_batch_size)
        logger.info("  Gradient Accumulation steps = %d", self.args.gradient_accumulation_steps)
        logger.info("  Total optimization steps = %d", t_total)
        logger.info("  Logging steps = %d", self.args.logging_steps)
        logger.info("  Save steps = %d", self.args.save_steps)

        global_step = 0
        tr_loss = 0.0
        self.model.zero_grad()

        train_iterator = trange(int(self.args.num_train_epochs), desc="Epoch")

        for _ in train_iterator:
            epoch_iterator = tqdm(train_dataloader, desc="Iteration")
            for step, batch in enumerate(epoch_iterator):
                self.model.train()
                batch = tuple(t.to(self.device) for t in batch)  # GPU or CPU

                inputs = {'input_ids': batch[0],
                          'attention_mask': batch[1],
                          'intent_label_ids': batch[3],
                          'slot_labels_ids': batch[4]}
                if self.args.model_type != 'distilbert':
                    inputs['token_type_ids'] = batch[2]
                outputs = self.model(**inputs)
                loss = outputs[0]

                if self.args.gradient_accumulation_steps > 1:
                    loss = loss / self.args.gradient_accumulation_steps

                loss.backward()

                tr_loss += loss.item()
                if (step + 1) % self.args.gradient_accumulation_steps == 0:
                    torch.nn.utils.clip_grad_norm_(self.model.parameters(), self.args.max_grad_norm)

                    optimizer.step()
                    scheduler.step()  # Update learning rate schedule
                    self.model.zero_grad()
                    global_step += 1

                    if self.args.logging_steps > 0 and global_step % self.args.logging_steps == 0:
                        self.evaluate("dev")

                    if self.args.save_steps > 0 and global_step % self.args.save_steps == 0:
                        self.save_model()

                if 0 < self.args.max_steps < global_step:
                    epoch_iterator.close()
                    break

            if 0 < self.args.max_steps < global_step:
                train_iterator.close()
                break

        return global_step, tr_loss / global_step

3.模型评估

    def evaluate(self, mode):
        if mode == 'test':
            dataset = self.test_dataset
        elif mode == 'dev':
            dataset = self.dev_dataset
        else:
            raise Exception("Only dev and test dataset available")

        eval_sampler = SequentialSampler(dataset)
        eval_dataloader = DataLoader(dataset, sampler=eval_sampler, batch_size=self.args.eval_batch_size)

        # Eval!
        logger.info("***** Running evaluation on %s dataset *****", mode)
        logger.info("  Num examples = %d", len(dataset))
        logger.info("  Batch size = %d", self.args.eval_batch_size)
        eval_loss = 0.0
        nb_eval_steps = 0
        intent_preds = None
        slot_preds = None
        out_intent_label_ids = None
        out_slot_labels_ids = None

        self.model.eval()

        for batch in tqdm(eval_dataloader, desc="Evaluating"):
            batch = tuple(t.to(self.device) for t in batch)
            with torch.no_grad():
                inputs = {'input_ids': batch[0],
                          'attention_mask': batch[1],
                          'intent_label_ids': batch[3],
                          'slot_labels_ids': batch[4]}
                if self.args.model_type != 'distilbert':
                    inputs['token_type_ids'] = batch[2]
                outputs = self.model(**inputs)
                tmp_eval_loss, (intent_logits, slot_logits) = outputs[:2]

                eval_loss += tmp_eval_loss.mean().item()
            nb_eval_steps += 1

            # Intent prediction
            if intent_preds is None:
                intent_preds = intent_logits.detach().cpu().numpy()
                out_intent_label_ids = inputs['intent_label_ids'].detach().cpu().numpy()
            else:
                intent_preds = np.append(intent_preds, intent_logits.detach().cpu().numpy(), axis=0)
                out_intent_label_ids = np.append(
                    out_intent_label_ids, inputs['intent_label_ids'].detach().cpu().numpy(), axis=0)

            # Slot prediction
            if slot_preds is None:
                if self.args.use_crf:
                    # decode() in `torchcrf` returns list with best index directly
                    slot_preds = np.array(self.model.crf.decode(slot_logits))
                else:
                    slot_preds = slot_logits.detach().cpu().numpy()

                out_slot_labels_ids = inputs["slot_labels_ids"].detach().cpu().numpy()
            else:
                if self.args.use_crf:
                    slot_preds = np.append(slot_preds, np.array(self.model.crf.decode(slot_logits)), axis=0)
                else:
                    slot_preds = np.append(slot_preds, slot_logits.detach().cpu().numpy(), axis=0)

                out_slot_labels_ids = np.append(out_slot_labels_ids, inputs["slot_labels_ids"].detach().cpu().numpy(), axis=0)

        eval_loss = eval_loss / nb_eval_steps
        results = {
            "loss": eval_loss
        }

        # Intent result
        intent_preds = np.argmax(intent_preds, axis=1)

        # Slot result
        if not self.args.use_crf:
            slot_preds = np.argmax(slot_preds, axis=2)
        slot_label_map = {i: label for i, label in enumerate(self.slot_label_lst)}
        out_slot_label_list = [[] for _ in range(out_slot_labels_ids.shape[0])]
        slot_preds_list = [[] for _ in range(out_slot_labels_ids.shape[0])]

        for i in range(out_slot_labels_ids.shape[0]):
            for j in range(out_slot_labels_ids.shape[1]):
                if out_slot_labels_ids[i, j] != self.pad_token_label_id:
                    out_slot_label_list[i].append(slot_label_map[out_slot_labels_ids[i][j]])
                    slot_preds_list[i].append(slot_label_map[slot_preds[i][j]])

        total_result = compute_metrics(intent_preds, out_intent_label_ids, slot_preds_list, out_slot_label_list)
        results.update(total_result)

        logger.info("***** Eval results *****")
        for key in sorted(results.keys()):
            logger.info("  %s = %s", key, str(results[key]))

        return results

4.保存模型

    def save_model(self):
        # Save model checkpoint (Overwrite)
        if not os.path.exists(self.args.model_dir):
            os.makedirs(self.args.model_dir)
        model_to_save = self.model.module if hasattr(self.model, 'module') else self.model
        model_to_save.save_pretrained(self.args.model_dir)

        # Save training arguments together with the trained model
        torch.save(self.args, os.path.join(self.args.model_dir, 'training_args.bin'))
        logger.info("Saving model checkpoint to %s", self.args.model_dir)

5.加载模型

    def load_model(self):
        # Check whether model exists
        if not os.path.exists(self.args.model_dir):
            raise Exception("Model doesn't exists! Train first!")

        try:
            self.model = self.model_class.from_pretrained(self.args.model_dir,
                                                          args=self.args,
                                                          intent_label_lst=self.intent_label_lst,
                                                          slot_label_lst=self.slot_label_lst)
            self.model.to(self.device)
            logger.info("***** Model Loaded *****")
        except:
            raise Exception("Some model files might be missing...")

五、主函数

import argparse

from trainer import Trainer
from utils import init_logger, load_tokenizer, read_prediction_text, set_seed, MODEL_CLASSES, MODEL_PATH_MAP
from data_loader import load_and_cache_examples


def main(args):
    init_logger()
    set_seed(args)
    tokenizer = load_tokenizer(args)

    train_dataset = load_and_cache_examples(args, tokenizer, mode="train")
    dev_dataset = load_and_cache_examples(args, tokenizer, mode="dev")
    test_dataset = load_and_cache_examples(args, tokenizer, mode="test")

    trainer = Trainer(args, train_dataset, dev_dataset, test_dataset)

    if args.do_train:
        trainer.train()

    if args.do_eval:
        trainer.load_model()
        trainer.evaluate("test")


if __name__ == '__main__':
    parser = argparse.ArgumentParser()

    parser.add_argument("--task", default=None, required=True, type=str, help="The name of the task to train")
    parser.add_argument("--model_dir", default=None, required=True, type=str, help="Path to save, load model")
    parser.add_argument("--data_dir", default="./data", type=str, help="The input data dir")
    parser.add_argument("--intent_label_file", default="intent_label.txt", type=str, help="Intent Label file")
    parser.add_argument("--slot_label_file", default="slot_label.txt", type=str, help="Slot Label file")

    parser.add_argument("--model_type", default="bert", type=str, help="Model type selected in the list: " + ", ".join(MODEL_CLASSES.keys()))

    parser.add_argument('--seed', type=int, default=1234, help="random seed for initialization")
    parser.add_argument("--train_batch_size", default=32, type=int, help="Batch size for training.")
    parser.add_argument("--eval_batch_size", default=64, type=int, help="Batch size for evaluation.")
    parser.add_argument("--max_seq_len", default=50, type=int, help="The maximum total input sequence length after tokenization.")
    parser.add_argument("--learning_rate", default=5e-5, type=float, help="The initial learning rate for Adam.")
    parser.add_argument("--num_train_epochs", default=10.0, type=float, help="Total number of training epochs to perform.")
    parser.add_argument("--weight_decay", default=0.0, type=float, help="Weight decay if we apply some.")
    parser.add_argument('--gradient_accumulation_steps', type=int, default=1,
                        help="Number of updates steps to accumulate before performing a backward/update pass.")
    parser.add_argument("--adam_epsilon", default=1e-8, type=float, help="Epsilon for Adam optimizer.")
    parser.add_argument("--max_grad_norm", default=1.0, type=float, help="Max gradient norm.")
    parser.add_argument("--max_steps", default=-1, type=int, help="If > 0: set total number of training steps to perform. Override num_train_epochs.")
    parser.add_argument("--warmup_steps", default=0, type=int, help="Linear warmup over warmup_steps.")
    parser.add_argument("--dropout_rate", default=0.1, type=float, help="Dropout for fully-connected layers")

    parser.add_argument('--logging_steps', type=int, default=200, help="Log every X updates steps.")
    parser.add_argument('--save_steps', type=int, default=200, help="Save checkpoint every X updates steps.")

    parser.add_argument("--do_train", action="store_true", help="Whether to run training.")
    parser.add_argument("--do_eval", action="store_true", help="Whether to run eval on the test set.")
    parser.add_argument("--no_cuda", action="store_true", help="Avoid using CUDA when available")

    parser.add_argument("--ignore_index", default=0, type=int,
                        help='Specifies a target value that is ignored and does not contribute to the input gradient')

    parser.add_argument('--slot_loss_coef', type=float, default=1.0, help='Coefficient for the slot loss.')

    # CRF option
    parser.add_argument("--use_crf", action="store_true", help="Whether to use CRF")
    parser.add_argument("--slot_pad_label", default="PAD", type=str, help="Pad token for slot label pad (to be ignore when calculate loss)")

    args = parser.parse_args()

    args.model_name_or_path = MODEL_PATH_MAP[args.model_type]
    main(args)

六、训练参数设置

1.基础参数

--task atis 
--model_type bert 
--model_dir experiments/jointbert_0 
--do_train --do_eval 
--train_batch_size 8 
--learning_rate 5e-5

intent_acc = 0.92721164613
slot_f1 = 0.8046902345
sementic_frame_acc = 0.58566629339

2.设置线性层学习率

--task atis 
--model_type bert 
--model_dir experiments/jointbert_0 
--do_train --do_eval 
--train_batch_size 8 
--learning_rate 5e-5
--linear_learning_rate 5e-4

intent_acc = 0.95744680851
slot_f1 = 0.9156920928
sementic_frame_acc = 0.77939529675

3.加上CRF,设置CRF学习率

--task atis 
--model_type bert 
--model_dir experiments/jointbert_0 
--do_train --do_eval 
--train_batch_size 8 
--learning_rate 5e-5
--linear_learning_rate 5e-4
--use_crf
--crf_learning_rate 5e-5

intent_acc = 0.93281075
slot_f1 = 0.9227542817
sementic_frame_acc = 0.78275475923

4.增加CRF学习率数量级

--task atis 
--model_type bert 
--model_dir experiments/jointbert_0 
--do_train 
--do_eval 
--train_batch_size 8 
--learning_rate 5e-5
--linear_learning_rate 5e-4
--use_crf
--crf_learning_rate 5e-3

intent_acc = 0.94736842
slot_f1 = 0.93968253
sementic_frame_acc = 0.812989921

在这里插入图片描述
针对不同学习率训练模型,效果随着学习率数量级的增加有显著提升。

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

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

相关文章

【Unity3D】Shader常量、变量、结构体、函数

1 源码路径 Unity Shader 常量、变量、结构体、函数一般可以在 Unity Editor 安装目录下面的【Editor\Data\CGIncludes\UnityShader】目录下查看源码&#xff0c;主要源码文件如下&#xff1a; UnityCG.cgincUnityShaderUtilities.cgincUnityShaderVariables.cginc 2 Shader 常…

大数据技术架构(组件)33——Spark:Spark SQL--Join Type

2.2.2、Join Type2.2.2.1、Broadcast Hash Join (Not Shuffled)就是常说的MapJoin,join操作在map端进行的。场景&#xff1a;join的其中一张表要很小&#xff0c;可以放到Driver或者Executor端的内存中。原理:1、将小表的数据广播到所有的Executor端&#xff0c;利用collect算子…

微信小程序 数据绑定 Mustache语法怎么使用?

1.数据绑定的基本原则 ①在data中定义数据 ②在WXML中使用数据、 在页面对应的 .js 文件中。把数据定义到data对象中即可 在WXML文件中使用{{}}两个花括号加变量名称进行调用 以上使用方法&#xff0c;下面我么来实操 Mustache语法主要使用场景如下: 文本内容绑定 组件属性绑定…

Service

目录 文章目录目录本节实战1、Service1.Service概念2.Service存在的意义3.Pod与Service的关系2、三种IP3、定义 Service4、kube-proxy1.iptables2.ipvsiptables vs ipvs5、Service常见类型1.ClusterIP2.NodePort3.LoadBalancer4.ExternalName5.externalIPs6、Endpoints 与 Endp…

Java基础常见面试题(三)

String 字符型常量和字符串常量的区别&#xff1f; 形式上: 字符常量是单引号引起的一个字符&#xff0c;字符串常量是双引号引起的若干个字符&#xff1b; 含义上: 字符常量相当于一个整型值( ASCII 值)&#xff0c;可以参加表达式运算&#xff1b;字符串常量代表一个地址值…

STC15读取内部ID示例程序

STC15读取内部ID示例程序&#x1f389;本案例基于STC15F2K60S2为验证对象。 &#x1f4d1;STC15 ID序列介绍 STC15系列STC最新一代STC15系列单片机出厂时都具有全球唯一身份证号码(ID号)。最新STC15系列单片机的程序存储器的最后7个字节单元的值是全球唯一ID号&#xff0c;用…

使用阿里云IoT Studio建立物模型可视化界面

使用阿里云IoT Studio建立物模型可视化界面 上一篇文章介绍了如何使用ESP-01S上报数据到物模型&#xff1a;https://blog.csdn.net/weixin_46251230/article/details/128996719 这次使用阿里云IoT Studio建立物模型的Web页面 阿里云IoT Studio&#xff1a; https://studio.i…

02 图像通道处理

1 通道提取与合并 在数字图像处理中&#xff0c;图像通道是指一个图像中的颜色信息被分离为不同的颜色分量。常见的图像通道包括RGB通道、灰度通道、HSV通道等。 RGB通道是指将图像分离为红色、绿色和蓝色三个颜色通道&#xff0c;每个通道表示相应颜色的亮度。这种方式是最常…

RuntimeError: CUDA out of memory

今天在训练模型的时候突然报了显存不够的问题&#xff0c;然后分析了一下&#xff0c;找到了解决的办法&#xff0c;这里记录一下&#xff0c;方便以后查阅。 注&#xff1a;以下的解决方案是在模型测试而不是模型训练时出现这个报错的&#xff01; RuntimeError: CUDA out of…

基于JavaEE的智能化跨境电子商务平台的设计

技术&#xff1a;Java、JSP、框架等摘要&#xff1a;伴随着近年来互联网的迅猛发展&#xff0c;网上零售逐渐成为了一种影响广泛、方便快捷的购物渠道。我国网上零售业发展的步伐很快。在如今经济全球化的影响下&#xff0c;消费者的网购行为趋于开放化、多元化&#xff0c;对于…

设计模式-中介者模式详解

定义 中介模式的英文翻译是 Mediator Design Pattern。在 GoF 中的《设计模式》一书中&#xff0c;它是这样定义的&#xff1a; Mediator pattern defines a separate (mediator) object that encapsulates the interaction between a set of objects and the objects delega…

chatGPT都可以干什么呢?来一睹风采吧

文章目录1. 写代码2. 写文案3. 写剧本4. 写歌诗5. 写报告6. 查公式7. 写对联8. 写文章9. 做表格10. 做计划11. 等等1. 写代码 2. 写文案 3. 写剧本 4. 写歌诗 5. 写报告 这妥妥的翻译文&#xff0c;数据完全不对。 6. 查公式 傅里叶变换的时域性质有如下几点&#xff1a; 对…

Android 内存优化(基础轮)必看~

本次分享主要分为五个部分内容&#xff0c;第一部分内容是 5W2H 分析内存优化&#xff0c;第二部分内容是内存管理机制&#xff0c;第三部分内容是内存优化 SOP&#xff0c;第四部分内容是 内存优化指导原则&#xff0c; 最后一部分内容是总结与展望。 如果学完内存优化的基础论…

webgl深入理解视图矩阵

文章目录前言三角形构成三维物体视点、目标、正方向视图矩阵辅助函数&#xff1a;归一化、向量差、点积、叉积视图矩阵的数学表示与使用视图矩阵构建三维世界注意前言 在前面的学习中&#xff0c;已经得知了webgl是如何绘制二维图形&#xff0c;并进行仿射变换&#xff08;矩阵…

mysql的架构图

Mysql逻辑架构图主要分三层&#xff1a;1) 第一层负责连接处理&#xff0c;授权认证&#xff0c;安全等等每个客户端连接都会在服务器进程中拥有一个线程&#xff0c;服务器维护了一个线程池&#xff0c;因此不需要为每一个新建的连接创建或者销毁线程。当客户端连接到Mysql服务…

基于JavaEE的“三味”书屋网上售书系统

技术&#xff1a;Java、JSP等摘要&#xff1a;美国最先提出Internet的概念,如今,全球各地的人们纷纷加入到这个网络行列, 使 Internet 真正走向全球化。随着用户、网民越来越多,网络的范围也愈来愈大,领域也慢慢走向了多元化&#xff0c;一体化 。“三味”书屋设计就是网络浪潮…

GORM设计原理和实践(七)——GORM

文章目录一、重点内容&#xff1a;1、GROM设计原理2、GROM配置3、GROM使用即CRUD二、详细知识点介绍&#xff1a;1、GORM设计原理图2、SQL是怎么生成的3、GROM配置开启go model设置go model输入代理&#xff1a;导入依赖&#xff1a;4、GROM操作初体验代码&#xff1a;5、模型定…

【Shell1】shell语法,ssh/build/scp/upgrade,环境变量,自动升级bmc

文章目录1.shell语法&#xff1a;shell是用C语言编写的程序&#xff0c;是用户使用Linux的桥梁&#xff0c;硬件>内核(os)>shell>文件系统1.1 变量&#xff1a;readonly定义只读变量&#xff0c;unset删除变量1.2 函数&#xff1a;shell脚本传递的参数中包含空格&…

app逆向篇之安卓模拟器环境搭建

前言 本教程适配:安卓7以上的安卓模拟器(包括雷电9等安卓9的模拟器&#xff09; 准备工具 雷电模拟器面具debug版LSPosed 正式步骤 安装雷电模拟器&#xff0c;这里怎么安装就不需要说了吧安装好雷电模拟器之后应该能够在桌面上看到两个图标&#xff0c;如下&#xff1a; …

分页和mmap

文章目录一、内存分页1、基本概念2、分页机制下&#xff0c;虚拟地址和物理地址是如何映射的&#xff1f;3、快表(TLB)二、mmap基本原理和分类一、内存分页 1、基本概念 CPU并不是直接访问物理内存地址&#xff0c;而是通过虚拟地址空间来间接的访问物理内存地址。 页&#x…