李宏毅机器学习2022-HW7-BERT-Question Answering

news2024/12/22 23:05:04

文章目录

  • Task
  • Baseline
    • Medium
    • Strong
    • Boss
  • Code Link

Task

HW7的任务是通过BERT完成Question Answering。

数据预处理流程梳理

数据解压后包含3个json文件:hw7_train.json, hw7_dev.json, hw7_test.json。

DRCD: 台達閱讀理解資料集 Delta Reading Comprehension Dataset

ODSQA: Open-Domain Spoken Question Answering Dataset

  • train: DRCD + DRCD-TTS
    • 10524 paragraphs, 31690 questions
  • dev: DRCD + DRCD-TTS
    • 1490 paragraphs, 4131 questions
  • test: DRCD + ODSQA
    • 1586 paragraphs, 4957 questions

{train/dev/test}_questions:

  • List of dicts with the following keys:
  • id (int)
  • paragraph_id (int)
  • question_text (string)
  • answer_text (string)
  • answer_start (int)
  • answer_end (int)

{train/dev/test}_paragraphs:

  • List of strings
  • paragraph_ids in questions correspond to indexs in paragraphs
  • A paragraph may be used by several questions

读取这三个文件,每个文件返回相应的question数据和paragraph数据,都是文本数据,不能作为模型的输入。

利用Tokenization将question和paragraph文本数据先按token为单位分开,再转换为tokens_to_ids数字数据。Dataset选取paragraph中固定长度的片段(固定长度为150),片段需包含answer部分,然后使用Tokenization 以CLS + question + SEP + document+ CLS + padding(不足的补0)的形式作为训练输入。

Total sequence length = question length + paragraph length + 3 (special tokens)
Maximum input sequence length of BERT is restricted to 512

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

training

在这里插入图片描述

testing

对于每个窗口,模型预测一个开始分数和一个结束分数,取最大值作为答案

在这里插入图片描述

Baseline

Medium

应用linear learning rate decay+change doc_stride

这里linear learning rate decay选用了两种方法

  • 手动调整学习率

    假设初始学习率为 η 0 η_0 η0,总的步骤数为 T T T,那么在第 t t t步时的学习率 η t η_t ηt 可以表示为:

    η t = η 0 − η 0 T × t η_t=η_0−\frac{η_0}{T}×t ηt=η0Tη0×t

    其中:

    • η 0 η_0 η0 是初始学习率。
    • T T T是总的步骤数(total_step)。
    • t t t 是当前的步骤数(从 0 开始计数)。

    optimizer.param_groups[0]["lr"] -= learning_rate / total_step η t = η t − η 0 T η t η_t=η_t−\frac{η_0}{T}η_t ηt=ηtTη0ηt

    • optimizer.param_groups[0]["lr"] 对应 η t η_t ηt
    • learning_rate 对应 η 0 η_0 η0
    • total_step 对应 T T T
    • i 对应 t t t
    # Medium--Learning rate dacay
    # Method 1: adjust learning rate manually
    total_step = 1000
    for i in range(total_step):
        optimizer.param_groups[0]["lr"] -= learning_rate / total_step
    
  • 通过scheduler自动调整学习率

    • (recommend) transformer
    • torch.optim
    # Method 2: Adjust learning rate automatically by scheduler
    
    # (Recommend) https://huggingface.co/transformers/main_classes/optimizer_schedules.html#transformers.get_linear_schedule_with_warmup
    from transformers import get_linear_schedule_with_warmup
    scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=100, num_training_steps=1000)
    
    # https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate
    # 这里如果要用pytorch的ExponentialLR,一定要导入optim模块,并且前面的AdamW是从transformers中import的这里要重新import
    import torch.optim as optim
    optimizer = optim.AdamW(model.parameters(), lr=learning_rate)
    scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
    

change doc_stride在QA_Dataset的时候修改段落滑动窗口的步长

##### TODO: Change value of doc_stride #####
# 段落滑动窗口的步长
self.doc_stride = 30  # Medium

Strong

应用➢ Improve preprocessing ➢ Try other pretrained models

  • 尝试其他预训练模型

比如bert-base-multilingual-case,因为它可以避免英文无法tokenization输出[UNK],但是计算量大

model = BertForQuestionAnswering.from_pretrained("hfl/chinese-macbert-large").to(device)
tokenizer = BertTokenizerFast.from_pretrained("hfl/chinese-macbert-large")
  • preprocessing ,在QA_Dataset中修改截取答案的窗口

    1. 随机窗口选择 Random Window Selection
      随机选择窗口的起始位置

      • 随机范围的下界
        start_min = max(0, answer_end_token - self.max_paragraph_len + 1) 答案结束位置向前移动 self.max_paragraph_len - 1 个标记后的位置和 0 较大的那个
      • 随机范围的上界
        start_max = min(answer_start_token, len(tokenized_paragraph) - self.max_paragraph_len)
        • len(tokenized_paragraph) - self.max_paragraph_len:计算段落长度减去窗口长度后的位置,确保窗口不会超出段落末尾。
        • min(answer_start_token, ...):确保上界不超过答案开始位置,避免答案被截断。
      • 随机选择
        paragraph_start = random.randint(start_min, start_max)在计算出的下界和上界之间随机选择一个整数作为窗口的起始位置。
      • 计算窗口结束位置
        paragraph_end = paragraph_start + self.max_paragraph_len确保窗口长度为 self.max_paragraph_len
    2. 滑动窗口大小 Dynamic window size

            ##### TODO: Preprocessing Strong #####
            # Hint: How to prevent model from learning something it should not learn
    
            if self.split == "train":
                # Convert answer's start/end positions in paragraph_text to start/end positions in tokenized_paragraph
                answer_start_token = tokenized_paragraph.char_to_token(question["answer_start"])
                answer_end_token = tokenized_paragraph.char_to_token(question["answer_end"])
    
                # A single window is obtained by slicing the portion of paragraph containing the answer
                # 在training中paragraph的截取依据的是answer的position id
                """
                mid = (answer_start_token + answer_end_token) // 2
                paragraph_start = max(0, min(mid - self.max_paragraph_len // 2, len(tokenized_paragraph) - self.max_paragraph_len))
                paragraph_end = paragraph_start + self.max_paragraph_len"""
                # Strong
                # Method 1: Random window selection
                start_min = max(0, answer_end_token - self.max_paragraph_len + 1)  # 计算答案结束位置向前移动 self.max_paragraph_len - 1 个标记后的位置
                start_max = min(answer_start_token, len(tokenized_paragraph) - self.max_paragraph_len)
                start_max = max(start_min, start_max)
                paragraph_start = random.randint(start_min, start_max + 1)
                paragraph_end = paragraph_start + self.max_paragraph_len
                
                """
                # Method 2: Dynamic window size 
                # 这个会造成窗口的大小大于max_paragraph_len,那么会造成输入序列的长度不一致,后面padding也要改,这里暂不采用
                answer_length = answer_end_token - answer_start_token
                dynamic_window_size = max(self.max_paragraph_len, answer_length + 20)  # 添加一些额外的空间
                paragraph_start = max(0, min(answer_start_token - dynamic_window_size // 2, len(tokenized_paragraph) - dynamic_window_size))
                paragraph_end = paragraph_start + dynamic_window_size
                """
    
    

Boss

➢ Improve postprocessing ➢ Further improve the above hints

doc_stride + max_length+ learning rate scheduler + preprocessing+ postprocessing + new model + no validation

与strong baseline相比,最大的改变有两个,一是换pretrain model,在hugging face中搜索chinese + QA的模型,根据model card描述选择最好的模型,使用后大概提升2.5%的精度,二是更近一步的postprocessing,查看提交文件可看到很多answer包含CLS, SEP, UNK等字符,CLS和SEP的出现表示预测位置有误,UNK的出现说明有某些字符无法正常编码解码(例如一些生僻字),错误字符的问题均可在evaluate函数中改进,这个步骤提升了大概1%的精度。其他的修改主要是针对overfitting问题,包括减少了learning rate,提升dataset里面的paragraph max length, 将validation集合和train集合进行合并等。另外可使用的办法有ensemble,大概能提升0.5%的精度,改变random seed,也有提升的可能性。

if start_index > end_index or start_index < paragraph_start or end_index > paragraph_end:
    continue
    
if '[UNK]' in answer:
    print('发现 [UNK],这表明有文字无法编码, 使用原始文本')
    #print("Paragraph:", paragraph)
    #print("Paragraph:", paragraph_tokenized.tokens)
    print('--直接解码预测:', answer)
    #找到原始文本中对应的位置
    raw_start =  paragraph_tokenized.token_to_chars(origin_start)[0]
    raw_end = paragraph_tokenized.token_to_chars(origin_end)[1]
    answer = paragraph[raw_start:raw_end]
    print('--原始文本预测:',answer)

Code Link

github

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

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

相关文章

若依框架篇-若依框架搭建具体过程、后端源代码分析、功能详解(权限控制、数据字典、定时任务、代码生成、表单构建、接口测试)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 若依框架概述 1.1 若依构建 1.2 后端项目搭建 1.3 前端项目搭建 2.0 利用若依框架生成前后端代码案例 3.0 功能详解 3.1 功能详解 - 权限控制 3.1.1 使用权限控制…

Linux权限和开发工具(1)

文章目录 1.Linux根目录的相关文件夹2.Linux软件管理器yum3.Linux编辑器-vim的基础使用1.命令模式下一些命令:有关光标的操作:有关复制删除的操作:有关字符替换的相关操作:有关注释的相关操作: 2.插入模式3.底行模式下一些命令:实现双窗口 4.vim命令 4.vim配置5.Linux编译器-gc…

华为OD机试 - 文本统计分析(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

在 Django 模板文件中出现错误:Could not parse the remainder: ‘!=0‘ from ‘!=0‘

问题在于我写了一条关于 {% if %} 标签中关于运算符 !0 的判断&#xff0c;出现 Could not parse the remainder: !0 from !0 错误 问题分析&#xff1a; 1、已确定 student 对象已经传递到模板中&#xff0c;并且 score 属性存在 2、确定 student.score 的值是可以与 0 进行…

前端开发设计模式——命令模式

目录 一、命令模式的定义和特点 1.定义&#xff1a; 2. 特点&#xff1a; 二、命令模式的结构与原理 1.结构&#xff1a; 2.原理&#xff1a; 三、命令模式的实现方式 1.定义接口命令&#xff1a; 2.创建具体的命令类&#xff1a; 3.定义接收者&…

blender分离含有多个动作的模型,并导出含有材质的fbx模型

问题背景 笔者是模型小白&#xff0c;需要将网络上下载的fbx模型中的动作&#xff0c;分离成单独的动作模型&#xff0c;经过3天摸爬滚打&#xff0c;先后使用了blender&#xff0c;3d max&#xff0c;unity&#xff0c;最终用blender完成&#xff0c;期间参考了众多网络上大佬…

编译器对连续构造的优化

一&#xff1a;优化的规则 在一行代码中连续进行&#xff1a;构造构造/构造拷贝构造/拷贝构造拷贝构造 都会合二为一 如下&#xff1a; a&#xff1a;构造构造->构造 b&#xff1a;构造拷贝构造->构造 c&#xff1a;拷贝构造拷贝构造->拷贝构造 注意&#xff…

KubeSphere v4 安装指南

日前&#xff0c;KubeSphere v4 发布&#xff0c;相较于之前的版本&#xff0c;新版本在架构上有了颠覆性的变化。为了让社区的各位小伙伴能够丝滑的从旧版本过渡到新版本&#xff0c;我们特别推出本篇安装指南文章&#xff0c;以供参考。 关于 KubeSphere v4 的介绍&#xff…

施磊C++ | 进阶学习笔记 | 5.设计模式

五、设计模式 文章目录 五、设计模式1.设计模式三大类型概述一、创建型设计模式二、结构型设计模式三、行为型设计模式 2.设计模式三大原则3.单例模式1.饿汉单例模式2.懒汉单例模式 4.线程安全的懒汉单例模式1.锁双重判断2.简洁的线程安全懒汉单例模式 5.简单工厂(Simple Facto…

MySQL 8.4修改user的host属性值

MySQL 8.4修改user的host属性值 update mysql.user set host localhost where user mysql用户名; MySQL 8.4修改初始化后的默认密码-CSDN博客文章浏览阅读804次&#xff0c;点赞6次&#xff0c;收藏11次。先下载mysql的zip压缩包&#xff1a;MySQL :: Download MySQL Communi…

(CWRU)轴承故障诊数据集和代码全家桶

包括 完整的CWRU轴承故障数据集&#xff0c; 以及已经生成制作好的一维故障信号数据集、时频图像数据集&#xff0c;对应代码均可以运行 点击下载&#xff1a;数据集和代码全家桶 环境&#xff1a;python 3.9 任何环境安装或者代码问题&#xff0c;请联系作者沟通交流&#xf…

操作符详解(C 语言)

目录 一、操作符的分类二、算数操作符1. 除法操作符2. 取余操作符 三、位移操作符1. 进制2. 原码、反码和补码3. 左移操作符&#xff08;<<&#xff09;和右移操作符&#xff08;>>&#xff09; 四、位操作符1. 按位与 &2. 按位或 |3. 按位异或 ^4. 按位取反 ~…

2018 年 NLP 的 10 个令人兴奋的想法

一、说明 这篇文章收集了有影响力的 10 个想法&#xff0c;我们将来可能会看到更多。 对于每个想法&#xff0c;我们将重点介绍 1-2 篇执行良好的论文。为了保持列表简洁&#xff0c;这里没有涵盖所有相关工作。该列表必然是主观的&#xff0c;涵盖主要与迁移学习和泛化相关的想…

老照片修复工作流教程:用 ComfyUI 轻松还原历史记忆

你是否有过这样的遗憾&#xff1f; 那些珍贵的老照片因为时间的流逝&#xff0c;早已失去了当年的色彩&#xff0c;变得模糊、褪色&#xff0c;甚至破损&#xff1f; 今天带你了解如何使用 ComfyUI 的老照片修复工作流&#xff0c;通过简单的几步操作&#xff0c;在短短十几秒…

三亚旅游微信小程序的设计与实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

【深度学习代码调试1】环境配置篇(上) -- 安装PyTorch(安利方法:移除所有国内源,使用默认源)

【深度学习代码调试1】环境配置篇 -- 安装TensorFlow和PyTorch 写在最前面1. 创建新的Conda环境2. 安装PyTorch及相关库&#xff08;可以直接跳到2.3安装方法&#xff09;2.1 检查CUDA版本2.2 解决安装过程中常见问题2.2.1 超时问题&#xff08;这个不是最终解决方案&#xff0…

AUTOSAR_EXP_ARAComAPI的5章笔记(13)

☞返回总目录 5.4.7 事件&#xff08;Events&#xff09; 在骨架侧&#xff0c;服务实现负责通知事件的发生。如 5.4.2 RadarService Skeleton Class 所示&#xff0c;骨架为每个事件提供一个事件包装类的成员。骨架的事件包装类与代理的事件包装类看起来明显不同。 在骨架端…

论文阅读:On determining the hinterlands of China‘s foreign trade container ports

集装箱港口腹地的边界线&#xff0c;只要存在&#xff0c;就可以作为未来港口发展和基础设施规划的参考点。在早期划定中国港口腹地的努力中&#xff0c;要么考虑的港口数量有限&#xff0c;要么仅根据港口总吞吐量划定腹地。因此&#xff0c;这些研究都没有让我们清楚地了解共…

快速理解AUTOSAR CP的软件架构层次以及各层的作用

在 AUTOSAR CP 的架构中&#xff0c;软件分为 应用层 (App)、运行时环境 (RTE) 和 基础软件层 (BSW) 三个主要层级。下面是每一层的主要功能与简单的代码示例来展示它们之间的关系。 1. 概述 应用层 (App)&#xff1a;包含应用程序代码&#xff0c;主要实现业务逻辑。应用层通…

DeepFM模型代码详解

直到看到这篇文章&#xff0c;我才搞明白类别特征怎么做lookup的&#xff0c;也看明白了代码逻辑。如果你看完没懂&#xff0c;私信留下wx&#xff0c;给你讲懂。 1、Deepfm 的原理&#xff0c;DeepFM 是一个模型还是代表了一类模型&#xff0c;DeepFM 对 FM 做了什么样的改进…