BERT模型的OneFlow实现
模型概述
BERT(Bidirectional Encoder Representations from Transformers)是NLP领域的一种预训练模型。本案例中,基于论文BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding实现了BERT模型的OneFlow版本。
模型架构

BERT 在实际应用中往往分为两步:
• 首先,预训练得到 BERT 语言模型;
• 然后,为满足下游应用,在得到的 BERT 语言模型的基础上,多加一层网络,并进行微调,得到下游应用。
快速开始
获取相关数据集
提供了完成 BERT 预训练及 SQuAD 微调的 OFRecord 数据集及相关数据文件,可以通过以下命令下载并解压:
wget https://oneflow-static.oss-cn-beijing.aliyuncs.com/oneflow-tutorial-attachments/bert_squad_dataset.zip
unzip bert_squad_dataset.zip
解压后的文件目录清单如下:
• bert_config.json、vocab.txt:制作 prediction json 文件需要的文件,来自google bert
• dev-v1.1/、dev-v1.1.json:SQuAD 检验集,用于打分
• part-0:预训练集样本(40个样本)
• train-v1.1:SQuAD 训练集,已经转为 ofrecord 数据集格式
以上各个文件将在下文的预训练任务、SQuAD 微调中使用到。
训练 BERT 模型
首先,克隆 OneFlow-Benchmark 仓库。
git clone https://github.com/Oneflow-Inc/OneFlow-Benchmark.git
cd OneFlow-Benchmark/LanguageModeling/BERT/
然后,通过以下命令,使用预训练好的 pretrain 模型以及小型样本集合,开始 BERT 预训练查看效果:
python ./run_pretraining.py
–gpu_num_per_node=1
–learning_rate=3e-5
–batch_size_per_device=1
–iter_num=3
–loss_print_every_n_iter=50
–seq_length=128
–max_predictions_per_seq=20
–num_hidden_layers=12
–num_attention_heads=12
–max_position_embeddings=512
–type_vocab_size=2
–vocab_size=30522
–attention_probs_dropout_prob=0.0
–hidden_dropout_prob=0.0
–hidden_size_per_head=64
–use_boxing_v2=True
–data_dir=./dataset/
–data_part_num=1
–log_dir=./bert_regresssioin_test/of
–loss_print_every_n_iter=5
–model_save_dir=./bert_regresssioin_test/of
–warmup_batches 831
–save_last_snapshot True
将获得类似以下输出:

Running bert: num_gpu_per_node = 1, num_nodes = 1.

gpu_num_per_node = 1
node_num = 1
node_list = None
learning_rate = 3e-05
weight_decay_rate = 0.01
batch_size_per_device = 1
iter_num = 20
warmup_batches = 831
log_every_n_iter = 1
data_dir = ./dataset/
data_part_num = 1
use_fp16 = None
use_boxing_v2 = True
loss_print_every_n_iter = 5
model_save_every_n_iter = 10000
model_save_dir = ./bert_regresssioin_test/of
save_last_snapshot = True
model_load_dir = None
log_dir = ./bert_regresssioin_test/of
seq_length = 128
max_predictions_per_seq = 20
num_hidden_layers = 12
num_attention_heads = 12
max_position_embeddings = 512
type_vocab_size = 2
vocab_size = 30522
attention_probs_dropout_prob = 0.0
hidden_dropout_prob = 0.0
hidden_size_per_head = 64

Time stamp: 2020-07-06-19:09:29
I0706 19:09:29.605840639 34801 ev_epoll_linux.c:82] Use of signals is disabled. Epoll engine will not be used
Init model on demand
iter 4, total_loss: 11.032, mlm_loss: 10.281, nsp_loss: 0.751, speed: 33.086(sec/batch), 0.151(sentences/sec)
iter 9, total_loss: 11.548, mlm_loss: 10.584, nsp_loss: 0.965, speed: 0.861(sec/batch), 5.806(sentences/sec)
iter 14, total_loss: 10.697, mlm_loss: 10.249, nsp_loss: 0.448, speed: 0.915(sec/batch), 5.463(sentences/sec)
iter 19, total_loss: 10.685, mlm_loss: 10.266, nsp_loss: 0.419, speed: 1.087(sec/batch), 4.602(sentences/sec)
Saving model to ./bert_regresssioin_test/of/last_snapshot.

average speed: 0.556(sentences/sec)

详细说明
脚本说明

脚本参数
run_pretraining.py通过命令行参数配置包括超参在内的训练环境,可以通过 run_pretraining.py --help查看,以下是这些参数作用的具体说明:
• gpu_num_per_node: 每个节点上 GPU 的数目,OneFlow 要求每个节点的 GPU 数目必须一致
• node_num: 节点数目,即分布式训练时的主机数目
• node_list: 节点列表,如果节点数大于1,则需要通过 node_list 指定节点列表,节点列表为字符串形式,采用逗号分隔,如–node_num=2 --node_list=“192.168.1.12,192.168.1.14”
• learning_rate: Learning rate
• weight_decay_rate:设置权重衰减率
• batch_size_per_device: 分布式训练时每个设备上的batch大小
• iter_num ITER_NUM: 训练的总轮数
• warmup_batches: 预热轮数,默认值为10000
• data_dir: OFRecord数据集的路径
• data_part_num:OFRecord数据集目录下的数据文件数目
• use_fp16: 是否使用fp16
• use_boxing_v2: 是否使用boxing v2
• loss_print_every_n_iter:训练中每隔多少轮打印一次训练信息(loss信息)
• model_save_every_n_iter: 训练中每隔多少轮保存一次模型
• model_save_dir: 模型存储路径
• save_last_snapshot:指定最后一轮训练完成后,模型保存路径
• model_load_dir:指定模型加载路径
• log_dir LOG_DIR:指定日志路径
• seq_length: 指定BERT句子长度,默认值为512
• max_predictions_per_seq: 默认值为80
• num_hidden_layers:隐藏层数目,默认值为24
• num_attention_heads: Attention头数目,默认值为16
使用完整的 Wikipedia + BookCorpus 数据集
如果需要从无到有进行 BERT 的 pretrain 训练,则需要使用较大的训练集。
如果感兴趣,可以通过 google-research BERT 的页面,下载 tfrecord 格式的数据集。再根据加载与准备OFRecord数据集中的方法,将 TFRecord 数据转为 OFRecord 数据集使用。
将 Tensorflow 的 BERT 模型转为 OneFlow 模型格式
如果想直接使用已经训练好的 pretrained 模型做 fine-tune 任务(如以下将展示的SQuAD),可以考虑直接从 google-research BERT 页面下载已经训练好的 BERT 模型。
再利用提供的 convert_tf_ckpt_to_of.py 脚本,将其转为 OneFlow 模型格式。转换过程如下:
首先,下载并解压某个版本的 BERT 模型,如 uncased_L-12_H-768_A-12。
wget https://storage.googleapis.com/bert_models/2020_02_20/uncased_L-12_H-768_A-12.zip
unzip uncased_L-12_H-768_A-12.zip -d uncased_L-12_H-768_A-12
然后,运行以下命令:
cd uncased_L-12_H-768_A-12/
cat > checkpoint <<ONEFLOW
model_checkpoint_path: “bert_model.ckpt”
all_model_checkpoint_paths: “bert_model.ckpt”
ONEFLOW
该命令将在解压目录下创建一个 checkpoint 文件,并写入以下内容:
model_checkpoint_path: “bert_model.ckpt”
all_model_checkpoint_paths: “bert_model.ckpt”
此时,已经准备好待转化的 TensorFlow 模型目录,整个模型目录的结构如下:
uncased_L-12_H-768_A-12
├── bert_config.json
├── bert_model.ckpt.data-00000-of-00001
├── bert_model.ckpt.index
├── checkpoint
└── vocab.txt
接着使用 convert_tf_ckpt_to_of.py 将 TensorFlow 模型转为 OneFlow 模型:
python convert_tf_ckpt_to_of.py
–tf_checkpoint_path ./uncased_L-12_H-768_A-12
–of_dump_path ./uncased_L-12_H-768_A-12-oneflow
以上命令,将转化好的 OneFlow 格式的模型保存在 ./uncased_L-12_H-768_A-12-oneflow 目录下,供后续微调训练(如:SQuAD)使用。
微调:SQuAD 问答任务
将 pretrained 模型修改为 SQuAD 模型
只需要在 BERT 的 backbone 基础上,加上一层 output 层,并修改 loss 的表达式即可,完整的代码可以查看 squad.py 脚本,以下是几处关键修改:
def SQuADTrain():
#…
backbone = bert_util.BertBackbone()

#在BERT的基础上加上一个全连接层
with flow.name_scope("cls-squad"):final_hidden = backbone.sequence_output()final_hidden_matrix = flow.reshape(final_hidden, [-1, hidden_size])logits = bert_util._FullyConnected(final_hidden_matrix,hidden_size,units=2,weight_initializer=bert_util.CreateInitializer(initializer_range),name='output')logits = flow.reshape(logits, [-1, seq_length, 2])start_logits = flow.slice(logits, [None, None, 0], [None, None, 1])end_logits = flow.slice(logits, [None, None, 1], [None, None, 1])#重新定义SQuAD任务的lossstart_loss = _ComputeLoss(start_logits, start_positions_blob, seq_length)end_loss = _ComputeLoss(end_logits, end_positions_blob, seq_length)total_loss = 0.5*(start_loss + end_loss)return total_loss

为了得到一个初始化的 squad 模型,通过以下脚本启动 squad 训练,并保存模型。
python ./run_squad.py
–gpu_num_per_node=1
–learning_rate=3e-5
–batch_size_per_device=2
–iter_num=50
–loss_print_every_n_iter=50
–seq_length=384
–max_predictions_per_seq=20
–num_hidden_layers=12
–num_attention_heads=12
–max_position_embeddings=512
–type_vocab_size=2
–vocab_size=30522
–attention_probs_dropout_prob=0.0
–hidden_dropout_prob=0.0
–hidden_size_per_head=64
–use_boxing_v2=True
–data_dir=./dataset/train-v1.1
–data_part_num=1
–log_dir=./bert_regresssioin_test/of
–model_save_dir=./bert_regresssioin_test/of
–warmup_batches 831
–save_last_snapshot True
完成训练后,在 ./bert_regresssioin_test/of/last_snapshot 中保存有初始化的 SQuAD 模型,将其与训练好的 BERT 合并后,进行微调(fine-tune)训练。
合并 pretrained 模型为 SQuAD 模型
SQuAD 模型是在 pretrained 模型基础上的扩充,需要参照模型的加载与保存中的“模型部分初始化和部分导入”方法,将训练好的 BERT pretrained 模型与初始化的 SQuAD 模型合并。
cp -R ./bert_regresssioin_test/of/last_snapshot ./squadModel
cp -R --remove-destination ./dataset/uncased_L-12_H-768_A-12_oneflow/* ./squadModel/
OneFlow 预训练模型的训练次数问题
OneFlow 生成的模型目录中,会有一个名为 System-Train-TrainStep-xxx 的子目录(xxx为作业函数的函数名),该子目录下的 out 文件中,保存有训练总迭代数,并且这个迭代数会用于动态调节训练过程的learning rate。
为了防止保存的迭代数影响到微调的训练,应该将out文件中的二进制数据清零:
cd System-Train-TrainStep-xxx
xxd -r > out <<ONEFLOW
00000000: 0000 0000 0000 0000
ONEFLOW
如果使用的是由 TensorFlow 转过来的预训练模型,则可以省去这个步骤。
开始 SQuAD 训练
通过 run_suqad.py 脚本,开始训练 SQuAD 模型,主要配置如下:
• 使用以上合并得到的 SQuAD 模型 ./squadModel
• 采用 SQuAD v1.1 作为训练集
• epoch = 3 (iternum = 886413/(48) = 8310)
• learning rate = 3e-5
python ./run_squad.py
–gpu_num_per_node=4
–learning_rate=3e-5
–batch_size_per_device=8
–iter_num=8310
–loss_print_every_n_iter=50
–seq_length=384
–max_predictions_per_seq=20
–num_hidden_layers=12
–num_attention_heads=12
–max_position_embeddings=512
–type_vocab_size=2
–vocab_size=30522
–attention_probs_dropout_prob=0.0
–hidden_dropout_prob=0.0
–hidden_size_per_head=64
–use_boxing_v2=True
–data_dir=./dataset/train-v1.1
–data_part_num=8
–log_dir=./bert_regresssioin_test/of
–model_save_dir=./bert_regresssioin_test/of
–warmup_batches 831
–save_last_snapshot True
–model_load_dir=./squadModel
预测及打分
生成为了生成 Preidiction File 格式的 json 文件,先将预测结果保存为 npy 文件,再使用 google BERT的run_squad.py 中的 write_predictions 函数,转化为 json 格式。
利用 run_squad_predict.py 生成 all_results.npy 文件:
python run_squad_predict.py
–gpu_num_per_node=1
–batch_size_per_device=4
–iter_num=2709
–seq_length=384
–max_predictions_per_seq=20
–num_hidden_layers=12
–num_attention_heads=12
–max_position_embeddings=512
–type_vocab_size=2
–vocab_size=30522
–attention_probs_dropout_prob=0.0
–hidden_dropout_prob=0.0
–hidden_size_per_head=64
–use_boxing_v2=True
–data_part_num=1
–data_dir=./dataset/dev-v1.1
–log_dir=./bert_regresssioin_test/of
–model_load_dir=path/to/squadModel
–warmup_batches 831
注意将以上 model_load_dir 修改为 训练好的 squadModel。
得到 all_results.npy 文件后,在google bert仓库目录下(注意该仓库的 tensorflow 版本为 tensorflow v1 ),运行提供的 npy2json.py (由 google bert 中的 run_squand.py 修改得来):
python npy2json.py
–vocab_file=./dataset/vocab.txt
–bert_config_file=./dataset/bert_config.json
–do_train=False
–do_predict=True
–all_results_file=./all_results.npy
–predict_file=./dataset/dev-v1.1.json
–max_seq_length=384
–doc_stride=128
–output_dir=./squad_base/
注意将 all_results_file 修改为上一步得到的 all_results.npy 的路径。
最终,得到 predictions.json 文件,可以使用 evaluate-v1.1.py 进行打分。
python evaluate-v1.1.py
./dataset/dev-v1.1.json
path/to/squad_base/predictions.json
分布式训练
如之前介绍脚本参数时描述:进行分布式训练,只需要在启动训练脚本式加入 node_num 选项指定主机数目及 node_list 选项即可:
python run_squad_predict.py
–gpu_num_per_node=1
–batch_size_per_device=4
–iter_num=2709
–seq_length=384
–max_predictions_per_seq=20
–num_hidden_layers=12
–num_attention_heads=12
–max_position_embeddings=512
–type_vocab_size=2
–vocab_size=30522
–attention_probs_dropout_prob=0.0
–hidden_dropout_prob=0.0
–hidden_size_per_head=64
–use_boxing_v2=True
–data_part_num=1
–data_dir=./dataset/dev-v1.1
–log_dir=./bert_regresssioin_test/of
–model_load_dir=path/to/squadModel
–warmup_batches 831
–node_num=2
–node_list=“192.168.1.12,192.168.1.14”

BERT模型的OneFlow实现相关推荐

  1. 各bert 模型下载

    20210618 https://huggingface.co/bert-base-chinese/tree/main bert 官方 https://mirrors.tuna.tsinghua.ed ...

  2. NLP突破性成果 BERT 模型详细解读 bert参数微调

    https://zhuanlan.zhihu.com/p/46997268 NLP突破性成果 BERT 模型详细解读 章鱼小丸子 不懂算法的产品经理不是好的程序员 ​关注她 82 人赞了该文章 Goo ...

  3. Pytorch | BERT模型实现,提供转换脚本【横扫NLP】

    <谷歌终于开源BERT代码:3 亿参数量,机器之心全面解读>,上周推送的这篇文章,全面解读基于TensorFlow实现的BERT代码.现在,PyTorch用户的福利来了:一个名为Huggi ...

  4. 干货 | 谷歌BERT模型fine-tune终极实践教程

    作者 | 奇点机智 从11月初开始,Google Research就陆续开源了BERT的各个版本.Google此次开源的BERT是通过TensorFlow高级API-- tf.estimator进行封 ...

  5. 从源码到实战:BERT模型训练营

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 开课吧教育 方向:NLP 之 BERT实战 都说BERT模型开启了NLP的新时代,更有" ...

  6. 通俗讲解从Transformer到BERT模型!

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:陈锴,中山大学  张泽,华东师范大学 近两年来,Bert模型非常受 ...

  7. 从Transformer到BERT模型

    目录: ELMo与Transformer的简单回顾 DAE与Masked Language Model BERT模型详解 BERT模型的不同训练方法 如何把BERT模型应用在实际项目中 如何对BERT ...

  8. ICLR2020 | StructBERT : 融合语言结构的BERT模型

    今天给大家介绍阿里巴巴达摩院在ICLR2020的一篇论文,该研究针对预训练语言模型BERT在预训练任务中忽略了语言结构的问题,作者对BERT进行扩展,通过加入语言结构到预训练任务中,其核心思想是在预训 ...

  9. build_transformer_model如果不返回keras的bert模型返回的是什么?

    build_transformer_model 还有两个问题: 1.如果不返回keras的bert模型返回的是什么? bert = build_transformer_model( config_pa ...

最新文章

  1. Windows 8部署系列PART2:部署先决条件准备
  2. Python web 开发:部署一个3行代码的wsgi app
  3. sticky list item
  4. arcgis dem栅格立体感_如何使用ArcGIS从DEM数据中提取水系
  5. php正则相对地址,php – 正则表达式将相对URL更改为绝对值
  6. 程序员面试题之从字节截断谈起
  7. Linux Shell编程笔记10 Shell数组的补充
  8. 信息系统项目10大管理-4W1H
  9. linux usb有线网卡驱动_Linux USB网卡驱动安装
  10. 你需要TrustedInstaller提供的权限才能对此文件进行更改
  11. GIS真正的魅力在哪?
  12. tkinter点击按钮实现图片的切换
  13. 画笔和画刷的种类和使用方法
  14. tf.matmul()
  15. 互联网晚报 | 1月13日 星期四 | 恒驰5首车下线;抖音电商测试快递服务“音尊达”;中国移动10086 App月底停止运营...
  16. Python 五行代码实现类似全能扫描王和office Lens的扫描彩色增强滤镜效果
  17. Filename和chunkFilename的区别
  18. github.io网页无法打开(连接不是私密连接)
  19. 我的物联网开发入门和踩坑历程
  20. 富士康用机器人取代了6万个工人

热门文章

  1. 简单两步,spring aop上手即用即会
  2. 2022-2028年中国绝热隔音材料行业投资分析及前景预测报告
  3. 用心真诚对待,懂你的人
  4. 第五周周记(国庆第三天)
  5. cookie 免密登录_python
  6. 数据类型转换pytorch
  7. logistic 损失函数的解释
  8. pytorch 动态调整学习率 重点
  9. PyTorch在NLP任务中使用预训练词向量
  10. LeetCode简单题之旋转字符串