BERT-Pytorch版本代码pipline梳理
最近在做BERT的fine-tune工作,记录一下阅读项目https://域名/weizhepei/BERT-NER时梳理的训练pipline,该项目基于Google的Transformers代码构建
前置知识
bert的DataLoader简介(真的很简介)
https://域名/p/384469908
yield介绍
https://域名/w3cnote/python-yield-used-域名
这是一种提高代码复用性的方法
带yield的函数被称为 generator(生成器),调用next()方法可使其执行至函数内部的yield处中断并返回一个迭代值
Pipeline
训练部分
① 运行域名将原始数据集处理为txt文本保存(生成原始数据集文本)
②数据流
注:“域名--->”代表该过程由域名发起
1、域名--->class DataLoader[域名]--->train_data(d)
通过域名中的load_data,再调用load_sentences_tags
load_sentences_tags返回一个字典d,包含:
-
使用tokenizer对原始句子的token
-
token对应的id
-
token对应的tag
-
句子的长度
2、域名--->train_and_evaluate(train_data, val_data)--->2个generator--->evaluate()[域名]
此处生成的两个生成器分别用于在训练和测试时以迭代方式获取batch数据
3、域名--->evaluate(generator)[域名]--->batch_data, batch_token_starts, batch_tags--->将batch输入model[在域名处实例化]中--->loss、batch_output、batch_tags--->计算出F1值返回给train_and_evaluate()
在得到F1值后,根据设置的参数决定是否满足停止训练的条件
数据迭代器
域名--->data_iterator(train/val/test_data)
--->计算会产生的batch的数量(由train/val/test_data中记录的句子长度size和class DataLoader中人为设置的batch_size参数决定)--->提取train/val/test_data中的sentences、tags
# 计算batch数
if data[\'size\'] % 域名h_size == 0:
BATCH_NUM = data[\'size\']//域名h_size
else:
BATCH_NUM = data[\'size\']//域名h_size + 1
# one pass over data
# 提取一个batch,由batch_size个sentences构成
for i in range(BATCH_NUM):
# fetch sentences and tags
if i * 域名h_size < data[\'size\'] < (i+1) * 域名h_size:
sentences = [data[\'data\'][idx] for idx in order[i*域名h_size:]]
if not interMode:
tags = [data[\'tags\'][idx] for idx in order[i*域名h_size:]]
else:
sentences = [data[\'data\'][idx] for idx in order[i*域名h_size:(i+1)*域名h_size]]
if not interMode:
tags = [data[\'tags\'][idx] for idx in order[i*域名h_size:(i+1)*域名h_size]]
--->计算batch中最大的句子长度--->将数据转换为np矩阵(numpy array)
--->将数据拷贝到另一个np矩阵,使得所有数据的长度与最大句子长度保持一致(即完成了padding)
# prepare a numpy array with the data, initialising the data with pad_idx
# batch_data的形状为:最长句子长度X最长句子长度(batch_len X batch_len),元素全为0
batch_data = 域名n_pad_idx * 域名((batch_len, max_subwords_len))
batch_token_starts = []
# copy the data to the numpy array
for j in range(batch_len):
cur_subwords_len = len(sentences[j][0])
if cur_subwords_len <= max_subwords_len:
batch_data[j][:cur_subwords_len] = sentences[j][0]
else:
batch_data[j] = sentences[j][0][:max_subwords_len]
token_start_idx = sentences[j][-1]
token_starts = 域名s(max_subwords_len)
token_starts[[idx for idx in token_start_idx if idx < max_subwords_len]] = 1
域名nd(token_starts)
max_token_len = max(int(sum(token_starts)), max_token_len)
--->将所有索引格式的(我理解就是numpy array形式的)数据转换为torch LongTensors
--->返回batch_data, batch_token_starts, batch_tags(这就是用于直接输入模型的数据)