关于人工智能:ERNIE-最棒的语义理解框架AWS-自然全力支持

3次阅读

共计 14445 个字符,预计需要花费 37 分钟才能阅读完成。

关注机器学习技术的童鞋可能曾经据说了,最近举办的寰球最大规模语义评测较量 SemEval 2020 中,语义了解框架 ERNIE 斩获了包含视觉媒体的要害文本片段开掘、多语攻击性语言检测和混合语种的情感剖析等在内的 5 项世界冠军!

ERNIE(Enhanced Representation through Knowledge Integration)旨在应用纯文本捕捉语义模式的根底之上,进一步通过常识加强的形式,联合语义中的常识关系来提供更加丰盛的结构化体现。所提出的常识加强语义示意模型,以及 2.0 版本构建的继续学习语义了解框架,在中英文等多个工作上超过业界最好模型。尤其在多项中文 NLP 工作中,ERNIE 的后果都能与 BERT 持平或有所晋升。

兴许有童鞋还不晓得,ERNIE 1.0 在公布之初,针对 BERT(Pre-training of Deep Bidirectional Transformers for Language Understanding)采纳了以字为单位的建模形式,但这种形式无奈学习到常识单元的残缺语义示意。起初曾有人提出应用常识实体来学习残缺概念的语义示意,并引入多源的数据语料进行训。因此从 2.0 版开始,ERNIE 提出了一种预训练框架,通过间断学习(Continual Learning)形式,应用多个不同的工作程序训练一个模型,这样,下个工作就会利用到后面工作的学习成绩,一直积攒新的常识。面对新工作,能够间接应用历史工作学习到的参数来初始化模型,以获取更好的训练成果。

接下来是一个更棒的音讯:AWS,尤其是 Amazon SageMaker 服务曾经提供了针对 ENRIE 2.0 的全面反对!

Amazon SageMaker 是亚马逊云计算(Amazon Web Service)的一项齐全托管的机器学习平台服务,算法工程师和数据科学家能够基于此平台疾速构建、训练和部署机器学习 (ML) 模型,而无需关注底层资源的治理和运维工作。它作为一个工具集,提供了用于机器学习的端到端的所有组件,包含数据标记、数据处理、算法设计、模型训练、训练调试、超参调优、模型部署、模型监控等,使得机器学习变得更为简略和轻松;同时,它依靠于 AWS 弱小的底层资源,提供了高性能 CPU、GPU、弹性推理加速卡等丰盛的计算资源和短缺的算力,使得模型研发和部署更为轻松和高效。

ERNIE 是基于开源深度学习平台 —— 飞桨(PaddlePaddle)来设计和实现的,本文会重点介绍如何通过 Amazon SageMaker 来实现基于此类第三方框架和自定义算法的模型预训练、增量训练和推理部署等机器学习工作,实现的技术细节和操作方法同样实用于其余相似的应用场景。

本文首先会重点介绍在 Amazon SageMaker 中应用 ERNIE 来进行模型预训练(pretraining)工作的办法。

Amazon SageMaker 模型训练介绍

Amazon SageMaker 为机器学习工作提供了根底算力和操作平台,在该平台上启动模型训练任务,包含如下过程:从 Amazon SageMaker 的计算集群中启用指定算力的机器实例,实例加载蕴含了算法和框架在内的容器镜像,并且加载寄存于内部存储(如 S3)的训练、验证、测试等数据集,启动训练脚本,实现模型迭代,保留模型等。而用户仅需做好相应参数配置,即可通过控制台点击或 API 调用形式实现。

训练任务的外围在于抉择蕴含算法和框架在内的容器镜像,对于训练镜像的起源,咱们既能够抉择由 Amazon SageMaker 提供的多种内置算法镜像,也能够抉择基于 Amazon SageMaker 内置框架(TensorFlow、Apache MXNet、PyTorch、Scikit-learn、XGBoost、Chainer)镜像,联合本人的代码来实现训练。如果须要应用本人的训练代码,并基于其余第三方框架或自带框架来实现模型训练,也能够通过自带容器的办法基于 Amazon SageMaker 来实现。

本文会针对最初一种状况,重点介绍在 Amazon SageMaker 上如何基于 PaddlePaddle 框架,联合自定义算法来实现 ERNIE 模型的预训练任务。该办法同样实用于其余自定义框架和算法的相似工作的实现。

通过自带容器办法实现自定义算法的模型预训练

对于 ERNIE 模型的预训练任务请参见此链接中的“预训练 (ERNIE 1.0)”章节。

如果在本地机器运行该预训练任务,须要实现以下两项工作:

  • 本地装置 PaddlePaddle 框架
  • 本地执行训练脚本

为将该工作从本地机器迁徙到 Amazon SageMaker,咱们须要针对这两项工作进行如下调整:
1. 本地装置 PaddlePaddle 框架 -> 构建适配于 SageMaker Container 的 PaddlePaddle 容器
1) Amazon SageMaker 是基于容器机制来实现机器学习工作的,对于自带框架和算法的场景,须要自行构建蕴含指标框架及相干依赖项在内的容器,并推送到 Amazon Elastic Container Registry(ECR)镜像注册表中,供 SageMaker 进行拉取和调用。
2) 在本文示例中,该局部工作的工程目录如下,该工程能够部署在 SageMaker Jupyter Notebook(举荐)或其余计算资源上。

/<for-docker-directory>/
├── ernie
│   ├── …
├── Dockerfile
├── requirements.txt
└── docker-actions.ipynb

阐明:

  • ernie:为源码中 ernie 框架实现代码,文件目录中的内容也进行了一些调整,次要包含:

    ~ 将根目录下的 config 文件夹拷贝到此目录下;
    ~ 为适配接口的调用,修改 pretrain_args.py、train.py 和 pretraining.py 三个文件中的局部代码,具体细节请见下文形容。

  • Dockerfile:Docker 形容文件
  • requirements.txt:为源码工程根目录下依赖项形容文件,这里的 requirements.txt 去掉 paddlepaddle-gpu==1.6.3.post107 一项;
  • docker-actions.ipynb:容器打包和上传代码,以笔记本形式调用。

3)编写 Dockerfile,本文示例的 Dockerfile 及阐明如下:

# 拉取预装置 PaddlePaddle 的镜像,具体镜像参考 https://www.paddlepaddle.org.cn/documentation/docs/zh/1.7/install/install_Docker.html#docker
 
FROM paddlepaddle/paddle:1.6.3-gpu-cuda10.0-cudnn7
 
# 标记维护者信息
 
MAINTAINER Amazon AI <sage-learner@amazon.com>
 
# 拷贝 requirements.txt 到容器代码目录
 
COPY requirements.txt /opt/ml/code/requirements.txt
 
# 装置依赖项
 
RUN pip install -r /opt/ml/code/requirements.txt
 
# 装置 SageMaker Container
 
RUN pip install sagemaker-containers==2.6.1
 
# 将 git 工程中的 ernie 文件夹拷贝到容器的 /opt/ml/code 目录下
 
COPY ernie /opt/ml/code
 
# 定义 train.py 为训练任务脚本
 
ENV SAGEMAKER_PROGRAM train.py

阐明:

  • SageMaker Container 作为一个库,它能够运行脚本、训练算法或部署与 Amazon SageMaker 兼容的模型,它定义了咱们的装置代码、数据等资源在容器中的存储地位,咱们须要通过 Dockerfile 将要运行的代码保留在 SageMaker 容器所冀望的地位(/opt/ml/code),具体内容请参见这里和这里。
  • ernie 目录也依照 SageMaker Container 目录要求拷贝到 /opt/ml/code;
  • 设置环境变量 SAGEMAKER_PROGRAM,定义 train.py 为训练任务脚本。

4)执行 docker-actions.ipynb 内的容器打包和上传代码:

# 设置权限并构建容器
 
!chmod +x train.py
 
!docker build -t pd-ernie-pretrain:v1 .
 
# 获取 ECR login
 
!$(aws ecr get-login --no-include-email --region us-west-2)
 
# 容器打标签
 
!docker tag pd-ernie-pretrain:v1 <your-aws-account>.dkr.ecr.<region>.amazonaws.com/<    
 
repository>:pd-ernie-pretrain
 
# 将容器推送到 ECR
 
!docker push "<your-aws-account>.dkr.ecr.<region>.amazonaws.com/<         
 
repository>:pd-ernie-pretrain"

这样,在咱们的 AWS 账号 ECR 服务的指定存储库中就蕴含了一个集成 PaddlePaddle 框架和 ERNIE 工程的模型训练容器。请记住该容器在存储库中的名称”<your-aws-account>.dkr.ecr.<region>.amazonaws.com/<repository>:pd-ernie-pretrain”,供 Amazon SageMaker 后续调用。

2. 本地执行训练脚本 -> 通过 API 形式在 Amazon SageMaker 上启动训练任务
本地执行训练 ERNIE 预训练的脚本为 script/zh_task/pretrain.sh,其中外围的训练命令为:

python ./ernie/train.py --use_cuda True \
 
                --is_distributed False\
 
                --use_fast_executor True \
 
                --weight_sharing True \
 
                --in_tokens true \
 
                --batch_size 8192 \
 
                --vocab_path ./config/vocab.txt \
 
                --train_filelist ./data/train_filelist \
 
                --valid_filelist ./data/valid_filelist \
 
                --validation_steps 100 \
 
                --num_train_steps 1000000 \
 
                --checkpoints ./checkpoints \
 
                --save_steps 10000 \
 
                --ernie_config_path ./config/ernie_config.json \
 
                --learning_rate 1e-4 \
 
                --use_fp16 false \
 
                --weight_decay 0.01 \
 
                --max_seq_len 512 \
 
                --skip_steps 10

该命令模式也是咱们在本地机器上执行训练任务的惯例形式,当初咱们一起看一看如何将该命令转化为 API 参数在 Amazon SageMaker 上启动训练任务。

该命令的参数次要包含 3 个局部:根底配置项(如 use_cuda)、输出数据门路(如 vocab_path)以及算法超参(如 learning_rate)。其中输出数据门路又分为根底配置数据门路(vocab_path、ernie_config_path)和数据集门路(train_filelist、valid_filelist)。在应用 Amazon SageMaker 进行模型训练过程中,最佳实际是将数据集寄存于内部的存储服务中,如 Amazon Simple Storage Service (S3)、Amazon Elastic File System (EFS)、Amazon FSx,告诉 SageMaker 拉取相应数据集进行计算工作。因而,这里的 train_filelist 和 valid_filelist 不会通过此参数传递形式将一个本地门路输出至训练脚本,而是通过 SageMaker 的 data channel 形式指定 S3 中的数据集的地位。去掉 train_filelist 和 valid_filelist 两个参数后,将残余参数结构如下_hyperparameters 的字典对象:

_hyperparameters = {
                            "use_cuda": True,
                            "is_distributed":False,
                            "use_fast_executor":True,
                            "weight_sharing":True,
                            "in_tokens":True,
                            "batch_size":8192,
                            "vocab_path":"./config/vocab.txt",
                            "num_train_steps":10000,
                            "checkpoints":"./checkpoints",
                            "save_steps":1000,
                            "ernie_config_path":"./config/ernie_config.json",
                            "learning_rate":"0.0001",
                            "use_fp16":False,
                            "weight_decay":0.01,
                            "max_seq_len":512,
                            "skip_steps":10,
                            "validation_steps": 100
              }

对于 train_filelist 和 valid_filelist 两个文件列表文件,咱们首先看一下 data 门路下的数据组成:

ERNIE/data/
├── demo_train_set.gz
├── demo_valid_set.gz
├── train_filelist
└── valid_filelist

其中 demo_train_set.gz 和 demo_valid_set.gz 为编码后的数据文件,train_filelist 为数据文件列表形容:

./data/demo_train_set.gz        1.1

在本文示例中,咱们扩大数据集及并修改文件列表如下:

ERNIE/data/
├── demo_train_set.gz
├── demo_train_set2.gz
├── demo_train_set3.gz
├── demo_train_set4.gz
├── demo_train_set5.gz
├── demo_valid_set.gz
├── demo_valid_set2.gz
├── train_filelist
└── valid_filelist

train_filelist:demo_train_set.gz      1.1
 
demo_train_set2.gz     1.1
 
demo_train_set3.gz     1.1
demo_train_set4.gz     1.1
 
demo_train_set5.gz     1.1
valid_filelist:demo_valid_set.gz      1.1
 
demo_valid_set2.gz     1.1

修改后,将数据集文件及文件列表上传至 S3:


<your-S3-bucket>/ernie/
├── train
│   ├── demo_train_set.gz
│   ├── demo_train_set2.gz
│   ├── demo_train_set3.gz
│   ├── demo_train_set4.gz
│   ├── demo_train_set5.gz
│   ├── train_filelist
├── valid
│   ├── demo_valid_set.gz
│   ├── demo_valid_set2.gz
└─ ├── valid_filelist

上传后,咱们构建一个数据通道字典,形容对应数据集在 S3 的存储地位:

_train_data = 'S3://{}/{}/{}'.format(bucket, folder, 'train')
_valid_data = 'S3://{}/{}/{}'.format(bucket,  folder, 'valid')
_data_channels = {'train': sagemaker.session.S3_input(_train_data),
               'valid': sagemaker.session.S3_input(_valid_data)}

SageMaker 收到此 data_channel 后会主动从 S3 对应地位拉取数据,下载到容器 /opt/ml/data/<channel_name>/ 门路下,这里的 < channel_name> 对应的是字典两个 Key:train 和 valid。

因而,为领导训练脚本从 /opt/ml/data/<channel_name>/ 门路下读取训练数据,须要对 pretrain_args.py、train.py 和 pretraining.py 进行一些修改(源工程是基于参数中的–train_filelist 和–valid_filelist 门路进行数据读取的),修改形式如下:

pretrain_args.py
 
data_g.add_arg("train_filelist",           str,  "","Path to training filelist.")
data_g.add_arg("valid_filelist",           str,  "","Path to valid filelist.")

批改为

data_g.add_arg("train_filelist",           str,  os.environ['SM_CHANNEL_TRAIN'] + "/train_filelist",  "Path to training filelist.")
data_g.add_arg("valid_filelist",           str,  os.environ['SM_CHANNEL_VALID'] + "/valid_filelist",  "Path to valid filelist.")

其中环境变量 os.environ [‘SM_CHANNEL_TRAIN’]即 /opt/ml/data/train,os.environ [‘SM_CHANNEL_VALID’]即 /opt/ml/data/valid,对应数据集在容器中存储的门路。

Pretraining.py
 
 
class ErnieDataReader(object):
 
    def __init__(self,
 
                 filelist,
 
                 vocab_path,
 
                 batch_size=4096,
 
                 in_tokens=True,
 
                 max_seq_len=512,
 
                 shuffle_files=True,
 
                 random_seed=1,
 
                 epoch=100,
 
                 voc_size=0,
 
                 is_test=False,
 
                 generate_neg_sample=False):

减少一个参数:data_tag,批改为

class ErnieDataReader(object):
 
    def __init__(self,
 
                 data_tag,
 
                 filelist,
 
                 vocab_path,
 
                 batch_size=4096,
 
                 in_tokens=True,
 
                 max_seq_len=512,
 
                 shuffle_files=True,
 
                 random_seed=1,
 
                 epoch=100,
 
                 voc_size=0,
 
                 is_test=False,
 
                 generate_neg_sample=False):

类内实现减少变量:

self.data_tag = data_tag

办法 data_generator 减少:

def data_generator(self):
 
        """data_generator"""
 
        def wrapper():
 
            def reader():
 
                for epoch in range(self.epoch):
 
                    self.current_epoch = epoch + 1
 
                    files = self.files
 
                    #during training, data are sliced by trainers
 
                    if self.shuffle_files:
 
                        start = epoch * self.total_file
 
                        end = start + self.total_file
 
                        files = [file_ for index, file_ in enumerate(self.files[start:end]) \
 
                            if index % self.trainer_nums == self.trainer_id]
 
                   
 
                    for index, file_ in enumerate(files):
 
                        file_, mask_word_prob = file_.strip().split("\t")
 
                        mask_word = (np.random.random() < float(mask_word_prob))
 
                        self.current_file_index = (index + 1) * self.trainer_nums
 
                        self.current_file = file_
 
                        ############ Modify - Start ############
 
                        env_str = 'SM_CHANNEL_' + self.data_tag.upper()
 
file_ = os.environ[env_str] + '/' + file_
 
                        ############ Modify – End ############
 
                        if mask_word:
 
                            self.mask_type = "mask_word"
 
                        else:
 
                            self.mask_type = "mask_char"

train.py 修改
办法 predict_wrapper:

filelist = args.test_filelist if args.do_test else args.valid_filelist
############ Modify - Start ############
tag = 'test' if args.do_test else 'valid
data_reader = ErnieDataReader(
        tag,
        filelist,
        vocab_path=args.vocab_path,
        batch_size=args.batch_size,
        voc_size=ernie_config['vocab_size'],
        shuffle_files=False,
        epoch=1,
        max_seq_len=args.max_seq_len,
        is_test=True)
############ Modify – End ############

办法 train

############ Modify - Start ############
data_reader = ErnieDataReader(
        data_tag = 'train',
        filelist=args.train_filelist,
        batch_size=args.batch_size,
        vocab_path=args.vocab_path,
        voc_size=ernie_config['vocab_size'],
        epoch=args.epoch,
        max_seq_len=args.max_seq_len,
        generate_neg_sample=args.generate_neg_sample)
############ Modify – End ############

在训练实现后,因为 Amazon SageMaker 会主动回收启动的计算资源,因而须要将模型保留至环境变量“SM_MODEL_DIR”对应的目录(/opt/ml/model/)下,SageMaker 会在回收资源之前主动将该目录下的模型文件上传至 S3 的指定目录中。

代码批改如下所示:
train.py,在办法 train 中,增加:

def train(args):
    …
    fluid.io.save_inference_model(dirname=os.environ['SM_MODEL_DIR'],
                                  feeded_var_names=['1','2','3','4'],
                                  target_vars=[next_sent_acc],
                                  executor=exe,
                                  main_program=train_program)

在模型训练的过程中,为察看训练指标的变动,可通过 API 参数设置指标提取形式,SageMaker 会主动过滤指标数值,写入到 Amazon CloudWatch 监控平台中,咱们能够在训练过程中及完结后察看指标的变动状况。

指标字典列表配置示例如下:

_metric_definitions = [{'Name': 'Training-loss' , 'Regex': 'loss: ([0-9\.]+)'}]

筹备好上述相应参数对象后,即可通过 API 启动 SageMaker 训练任务,该局部工作举荐在 SageMaker Jupyter Notebook 中实现:

# 导入 Sagemaker 库及 Python SDK
import sagemaker as sage
from sagemaker import get_execution_role
import boto3
 
# 获取会话及相干信息
sess = sage.Session()
client = boto3.client('sts')
account = client.get_caller_identity()['Account']
role = get_execution_role()
 
# 获取 S3 存储桶及门路
bucket = sess.default_bucket()
folder = 'ernie'
 
# 获取区域代码
my_session = boto3.session.Session()
region = my_session.region_name
 
# 获取寄存在 ECR 中的容器镜像名称
ecr_image = account + ".dkr.ecr." + region + ".amazonaws.com/sm-byo:pd-ernie-pretrain"
 
from sagemaker.estimator import Estimator
# 输出参数字典
_hyperparameters = {"use_cuda": True,
                    "is_distributed":False,
                    "use_fast_executor":True,
                    "weight_sharing":True,
                    "in_tokens":True,
                    "batch_size":8192,
                    "vocab_path":"./config/vocab.txt",
                    "num_train_steps":30,
                    "checkpoints":"./checkpoints",
                    "save_steps":10,
                    "ernie_config_path":"./config/ernie_config.json",
                    "learning_rate":"0.0001",
                    "use_fp16":False,
                    "weight_decay":0.01,
                    "max_seq_len":512,
                    "skip_steps":5,
                    "validation_steps": 20}
# 指标提取列表
_metric_definitions = [{'Name': 'Training-loss','Regex': 'loss: ([0-9\.]+)'}]
# 构建 SageMaker Estimator
estimator = Estimator(image_name=ecr_image, # 容器镜像
                      role=role,# 角色
                      train_instance_type='ml.p3.2xlarge', # 以后训练机型
                      train_instance_count=1, # 训练机器数量
                      hyperparameters = _hyperparameters, # 参数传递
                      metric_definitions = _metric_definitions, # 指标提取
                      output_path = 'S3://{}/{}/'.format(bucket,folder)) # 输入模型寄存在 S3 的门路
 
# 输出数据在 S3 门路,构建数据通道字典
train_data = 'S3://{}/{}/{}'.format(bucket, folder, 'train')
valid_data = 'S3://{}/{}/{}'.format(bucket,  folder, 'valid')
data_channels = {'train': sage.session.S3_input(train_data),
                'valid': sage.session.S3_input(valid_data)}
 
# 启动训练
estimator.fit(inputs=data_channels,  logs=True)

阐明

本示例选用单台 ml.p3.2xlarge 机型承载训练任务,该机器蕴含单张 Nvidia V100 显卡、8 核 CPU、61GB 内存。更多计算实例类型请参见这里。

训练过程中,能够通过 Amazon CloudWatch 实时可视化察看指标变动状况,点击 SageMaker 控制台对应的训练任务:

下拉至监控界面,能够点击查看算法指标、输入日志和实例指标。图中框选的 Trainig-loss 即为手动输入至 Amazon CloudWatch 的指标对象。

训练任务完结后,SageMaker 主动将模型文件保留至 S3 指定门路上,用于后续部署或迭代。

以上就是基于 Amazon SageMaker 通过自带容器办法实现自定义算法的模型预训练任务的根本介绍,该办法同样实用于基于其余第三方或自带框架的自定义工作的实现,对于通过自带容器形式实现模型优化和部署,敬请关注该系列文章的后续内容。

正文完
 0