目录
1 机器阅读理解任务介绍
2 基于Transfromers的解决方案
2.1 评估指标:
2.2 数据预处理:
在bert中,cls是起始符,而sep是分隔符。
2.3 模型结构:
3 代码实战演练(上)
1)导包:
2)数据集加载:
可以看到训练集、测试集、验证集已经都划分好了,这就省去了接下来数据集划分的步骤
简单浏览一下数据:
3)数据预处理:
导入tokenizer:
我们在前面简单浏览了一下数据集的格式,那么如何将数据格式转换为适合模型输入的标记化示例呢?
这个函数
process_func
是一个数据处理函数,用于将输入的示例数据进行处理,并生成适用于模型输入的标记化示例。具体来说,该函数接收一个
examples
参数,其中包含以下字段:
"question"
:问题文本"context"
:上下文文本"answers"
:答案列表,每个答案包含"answer_start"
和"text"
字段函数的主要步骤如下:
使用
tokenizer
对问题文本和上下文文本进行标记化,其中包括以下操作:
- 设置
max_length
为 384,限制标记化后的序列的最大长度- 使用
"only_second"
的截断策略,将上下文文本作为第二个序列进行截断- 使用
"max_length"
的填充策略,将序列填充到指定的最大长度从标记化后的序列中提取
offset_mapping
,该映射记录了每个标记在原始文本中的起始和结束位置。遍历
offset_mapping
,对每个标记化后的序列进行处理:
- 获取对应的答案信息(起始位置和文本内容)
- 根据答案在原始文本中的起始位置和结束位置,确定答案在标记化序列中的起始位置和结束位置
- 确定答案所在的上下文部分在标记化序列中的起始和结束位置,通过从左右两侧逼近答案位置来确定
- 将答案在标记化序列中的起始位置和结束位置加入到
start_positions
和end_positions
列表中将
start_positions
和end_positions
添加到标记化后的示例中,作为额外的字段。返回处理后的标记化示例。
对每一个示例数据进行同样的映射操作,就可以得到标准的适用于模型输入的数据格式:
4)创建模型:
5)配置训练参数:
6)设置训练器:
7)模型训练:
可以看到,这个要跑很久,在我的电脑上跑大概需要2h。
8)模型预测:
由于在本次实战中并未写模型评估部分的代码,那么我们如何得知训练效果呢?这个其实可以通过模型预测pipeline得到:
最后的预测结果如下所示: (其中这个分数就是其对应的评估指标)
这个是up主的
由于我采取了一些优化策略让模型能够跑起来,gradient_checkpointing=True,同时下调了batch的大小,所以可能造成最后的模型效果(得分)不是很好 :
4 代码实战演练(下)
前言:
在3中我们介绍了基于截断策略的机器阅读理解任务实现,有些部分并不完整。(比如没有评估函数,没有使用测试集测试,仅仅简单采用了截断策略)
那么接下来在本节中我们将学习基于滑动窗口策略的机器阅读理解任务实现。
如上图所示,这是一种简单的无重叠滑动窗口,有一个问题就是如果我们的答案是9-12,那么这个其实最后得到的答案就并不完整。
在实际中,我们会采用如下图所示的带有重叠overflow的滑动窗口
比如我们的最后答案在第一条中起始位置是2,结束位置是7;第二条和第三条中起始和结束位置都是cls 。
只需要起始和结束的下标加起来最大,且其不能出现在query位置就可以了。
所用到的数据集和预训练模型都和之前一致,在这次我们需要安装nltk包。
1)导包~2)数据集加载
和之前一致
3)数据预处理
return_overflowing_tokens=True,# 设置滑动窗口
我们可以直观地看到此时的特征中不止有'offset_mapping',还有'overflow_to_sample_mapping'
那么这个'overflow_to_sample_mapping'是什么呢?
在上文中,我们是选取了10条数据作为样本:sample_dataset = datasets["train"].select(range(10)),但此时这里却显示25条,这就说明已经使用了滑动窗口对超出最大长度的文本进行了分段。
我们可以打印以下前3条:
可以直观地发现此时这个滑动窗口仅仅是采取的简单的非重叠的,这是因为我们没有设置overflow
加下来,我们加入重叠部分,设置stride=128:
再次显示分段长度,我们可以直观发现此时的长度已经变为了29:
我们再打印一下前3段看一下效果:可以直观地看到,此时已经不是简单地分隔,已经有了重叠
对于process_func函数,主体是和之前一致地,不同的地方在于我们这里使用的是sample_mapping
可以直观看到,最后我们处理好的数据集中已经包含了offset_mapping这个特征。
可以看到query的部分已经是none了:
为了明确哪些段属于一段文本,需要对example和feature做一个映射:
4)获取模型输出:
根据模型输出的开始位置和结束位置的 logits,从候选答案中选择最佳的答案
这段代码是一个函数
get_result()
,用于根据模型的输出和输入数据获取预测结果和参考答案。函数的输入参数包括
start_logits
、end_logits
、examples
和features
。其中,
start_logits
: 一个包含开始位置预测结果的 numpy 数组。end_logits
: 一个包含结束位置预测结果的 numpy 数组。examples
: 一个包含输入示例的列表。每个示例包含一个id
、一个context
和一个answers
字段,用于保存问题的上下文和参考答案。features
: 一个字典,包含与示例相关的特征信息,如示例的标识、偏移映射等。函数的输出结果包括
predictions
和references
。
predictions
: 一个字典,包含模型的预测结果。键是示例的id
,值是模型预测的答案文本。references
: 一个字典,包含参考答案。键是示例的id
,值是示例中提供的参考答案文本。函数的主要逻辑是根据模型输出的开始位置和结束位置的 logits,从候选答案中选择最佳的答案。这里使用了
n_best
和max_answer_length
来控制最优答案候选和答案长度的限制。对于每个示例,通过遍历相关的特征,获取候选答案的开始和结束位置,从而得到最佳答案。最后,将预测的答案和参考答案存储在
predictions
和references
字典中,并返回这两个字典作为函数的输出结果。请注意,这段代码依赖于相关的数据结构和输入参数,可能需要结合其他代码和数据进行正确的使用.
5)评估函数
直接调用cmrc_eval
6)加载模型
7)配置训练参数
8)配置训练器:
9)模型训练
可以看到最后的效果还是不错的。