關注機器學習技術的童鞋可能已經據說了,最近舉辦的全球最大規模語義評測比賽 SemEval 2020中,語義理解框架 ERNIE 斬獲了包括視覺媒體的關鍵文本片斷挖掘、多語攻擊性語言檢測和混合語種的情感分析等在內的5項世界冠軍!html
ERNIE(Enhanced Representation through Knowledge Integration)旨在使用純文本捕獲語義模式的基礎之上,進一步經過知識加強的方式,結合語義中的知識關係來提供更加豐富的結構化表現。所提出的知識加強語義表示模型,以及2.0版本構建的持續學習語義理解框架,在中英文等多個任務上超越業界最好模型。尤爲在多項中文 NLP 任務中,ERNIE 的結果都能與 BERT 持平或有所提高。python
也許有童鞋還不知道,ERNIE 1.0在發佈之初,針對 BERT(Pre-training of Deep Bidirectional Transformers for Language Understanding)採用了以字爲單位的建模方式,但這種方式沒法學習到知識單元的完整語義表示。後來曾有人提出使用知識實體來學習完整概念的語義表示,並引入多源的數據語料進行訓。於是從2.0版開始,ERNIE 提出了一種預訓練框架,經過連續學習(Continual Learning)方式,使用多個不一樣的任務順序訓練一個模型,這樣,下個任務就會利用到前面任務的學習成果,不斷積累新的知識。面對新任務,能夠直接使用歷史任務學習到的參數來初始化模型,以獲取更好的訓練效果。git
接下來是一個更棒的消息:AWS,尤爲是 Amazon SageMaker 服務已經提供了針對ENRIE 2.0的全面支持!github
Amazon SageMaker 是亞馬遜雲計算(Amazon Web Service)的一項徹底託管的機器學習平臺服務,算法工程師和數據科學家能夠基於此平臺快速構建、訓練和部署機器學習(ML)模型,而無需關注底層資源的管理和運維工做。它做爲一個工具集,提供了用於機器學習的端到端的全部組件,包括數據標記、數據處理、算法設計、模型訓練、訓練調試、超參調優、模型部署、模型監控等,使得機器學習變得更爲簡單和輕鬆;同時,它依託於 AWS 強大的底層資源,提供了高性能 CPU、GPU、彈性推理加速卡等豐富的計算資源和充足的算力,使得模型研發和部署更爲輕鬆和高效。算法
ERNIE 是基於開源深度學習平臺 —— 飛槳(PaddlePaddle)來設計和實現的,本文會重點介紹如何經過 Amazon SageMaker 來實現基於此類第三方框架和自定義算法的模型預訓練、增量訓練和推理部署等機器學習任務,實現的技術細節和操做方法一樣適用於其餘相似的使用場景。docker
本文首先會重點介紹在 Amazon SageMaker 中使用 ERNIE 來進行模型預訓練(pretraining)任務的方法。json
Amazon SageMaker 爲機器學習任務提供了基礎算力和操做平臺,在該平臺上啓動模型訓練任務,包括以下過程:從 Amazon SageMaker 的計算集羣中啓用指定算力的機器實例,實例加載包含了算法和框架在內的容器鏡像,而且加載存放於外部存儲(如 S3)的訓練、驗證、測試等數據集,啓動訓練腳本,完成模型迭代,保存模型等。而用戶僅需作好相應參數配置,便可經過控制檯點擊或 API 調用方式完成。session
訓練任務的核心在於選擇包含算法和框架在內的容器鏡像,關於訓練鏡像的來源,咱們既能夠選擇由 Amazon SageMaker 提供的多種內置算法鏡像,也能夠選擇基於 Amazon SageMaker 內置框架(TensorFlow、Apache MXNet、PyTorch、Scikit-learn、XGBoost、Chainer)鏡像,結合本身的代碼來完成訓練。若是須要使用本身的訓練代碼,並基於其餘第三方框架或自帶框架來完成模型訓練,也能夠經過自帶容器的方法基於 Amazon SageMaker 來實現。app
本文會針對最後一種狀況,重點介紹在 Amazon SageMaker 上如何基於 PaddlePaddle 框架,結合自定義算法來完成 ERNIE 模型的預訓練任務。該方法一樣適用於其餘自定義框架和算法的相似任務的實現。框架
關於 ERNIE 模型的預訓練任務請參見此連接中的「預訓練 (ERNIE 1.0)」章節。
若是在本地機器運行該預訓練任務,須要完成如下兩項工做:
爲將該任務從本地機器遷移到 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
說明:
~ 將根目錄下的 config 文件夾拷貝到此目錄下;
~ 爲適配接口的調用,修正 pretrain_args.py、train.py 和 pretraining.py 三個文件中的部分代碼,具體細節請見下文描述。
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
說明:
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 經過自帶容器方法實現自定義算法的模型預訓練任務的基本介紹,該方法一樣適用於基於其餘第三方或自帶框架的自定義任務的實現,關於經過自帶容器方式實現模型優化和部署,敬請關注該系列文章的後續內容。