一、背景
利用業內數據構建知識圖譜是很多客戶正在面臨的問題,其中中文命名實體識別(Named Entity Recognition,簡稱NER)是構建知識圖譜的一個重要環節。我們在與客戶的交流中發現,現有的NER工具(比如Jiagu)對於特定領域的中文命名實體識別效果難以滿足業務需求,而且這些工具很難使用自定義數據集訓練。因此客戶迫切想使用業內最先進的算法在行業內數據集上進行訓練,以改進現有NER工具的不足。本文將介紹如何使用Amazon SageMaker運行基於TensorFlow的中文命名實體識別。
命名實體識別,是指識別文本中具有特定意義的實體,主要包括人名、地名、機構名、專有名詞等。命名實體識別是信息提取、問答系統、句法分析、機器翻譯、知識圖譜等應用領域的重要基礎工具。
英語中的命名實體具有比較明顯的形式標誌(即實體中的每個詞的第一個字母要大寫),所以實體邊界識別相對容易,任務的重點是確定實體的類別。和英語相比,中文命名實體識別任務更加複雜,而且相對於實體類別標註子任務,實體邊界的識別更加困難。
二、中文命名實體識別算法
NER一直是自然語言處理(NLP)領域中的研究熱點,從早期基於詞典和規則的方法,到傳統機器學習的方法,到近年來基於深度學習的方法,NER研究進展的大概趨勢大致如下圖所示。
早期的命名實體識別方法基本都是基於規則的。之後由於基於大規模的語料庫的統計方法在自然語言處理各個方面取得不錯的效果之後,一大批機器學習的方法也出現在命名實體類識別任務。
值得一提的是,由於深度學習在自然語言的廣泛應用,基於深度學習的命名實體識別方法也展現出不錯的效果,此類方法基本還是把命名實體識別當做序列標註任務來做,比較經典的方法是LSTM+CRF、BiLSTM+CRF。
我們知道,預訓練模型可以大幅提升計算機視覺的深度學習算法表現,而在NLP領域也是同理,預訓練語言模型可以有效提升文本分類、機器翻譯、命名實體識別等任務的效果。預訓練語言模型經歷了從詞嵌入(Word Embedding),到BERT,再到ALBERT的演進。
BERT的全稱是Bidirectional Encoder Representation from Transformers,即雙向Transformer的編碼器(Encoder),因為解碼器(Decoder)是不能獲得要預測的信息的。模型的主要創新點都在預訓練方法上,即用了Masked LM和Next Sentence Prediction兩種方法分別捕捉詞語和句子級別的表示。
ALBERT(見參考資料4)基於BERT,但有一些改進,它可以在主要基準測試上獲得最先進的性能,而參數卻減少了30%。比如,對於albert_base_zh,它只有原始BERT模型的10%的參數,但是保留了主要精度。
本文將使用預訓練語言模型ALBERT做中文命名實體識別,該項目基於開源的代碼修改而來(本文代碼見參考資料1,原始代碼見參考資料2),使用TensorFlow框架開發,在下一節,我們將展示如何在Amazon SageMaker中進行該模型的訓練。
三、在Amazon SageMaker中運行TensorFlow
本節將介紹如何使用Amazon SageMaker的自定義容器 (Bring Your Own Container,簡稱BYOC)和自定義腳本(Bring Your Own Script,簡稱BYOS)兩種方式來運行TensorFlow程序的訓練任務。首先我們來看下如何在Amazon SageMaker Notebook上運行這個項目,然後再把它運行在Amazon SageMaker上。
1. 在Amazon SageMaker Notebook上運行TensorFlow開原始碼
我們首先要創建Amazon SageMaker Notebook,然後下載代碼和數據,最後運行代碼。如果一切運行正常,我們就可以進行下一步工作——將該TensorFlow代碼運行到Amazon SageMaker中了。
1.1 創建Amazon SageMaker Notebook
我們首先要創建一個Amazon SageMaker Notebook,筆記本實例類型最好選擇ml.p2.xlarge,這樣就可以使用GPU進行訓練的測試了,卷大小建議改成10GB或以上,因為運行該項目需要下載一些額外的數據。
1.2 下載代碼和數據
筆記本啟動後,打開頁面上的終端,執行以下命令下載代碼:
cd ~/SageMaker
git clone https://github.com/whn09/albert-chinese-ner.git
執行以下命令下載和解壓數據(數據來源見參考資料3):
cd ~/SageMaker/albert-chinese-ner
wget https://storage.googleapis.com/albert_zh/albert_base_zh_additional_36k_steps.zip
unzip albert_base_zh_additional_36k_steps.zip -d albert_base_zh
1.3 運行代碼
我們需要進入一個虛擬環境tensorflow_p36,該環境預製了運行TensorFlow所需要的常用組件,運行run_train.sh進行訓練,命令如下:
cd ~/SageMaker/albert-chinese-ner
source activate tensorflow_p36
./run_train.sh
如果出現下面的輸出,說明運行結果正常,在實例類型為ml.p2.xlarge的筆記本中,訓練速度可以達到23個樣本/秒,如果是其他類型實例,速度可能有差異。
2. 自定義容器(BYOC)
自定義容器需要經歷準備Dockerfile,創建訓練的啟動腳本,創建鏡像並上傳到Amazon ECR,本地測試和Amazon SageMaker測試等步驟。完整執行過程見
tensorflow_bring_your_own.ipynb。
2.1 準備Dockerfile
我們首先需要準備Dockerfile,在其中安裝TensorFlow程序運行必須的環境,拷貝所有代碼到鏡像中。
FROM tensorflow/tensorflow:1.15.2-gpu-py3
ENV PATH="/opt/ml/code:${PATH}"
COPY ./ /opt/ml/code
WORKDIR /opt/ml/code
這裡我們需要了解Amazon SageMaker對於容器內目錄結構的要求,具體如下圖所示,訓練所需代碼放到/opt/ml/code目錄下,訓練所需數據放到/opt/ml/input/data目錄下,訓練輸出的模型放到/opt/ml/model目錄下,訓練結果文件或者日誌文件放到/opt/ml/output目錄下,訓練超參數文件是由Amazon SageMaker自動生成的,在/opt/ml/input/config目錄下。
2.2 創建訓練的啟動腳本
Amazon SageMaker在訓練時默認的啟動腳本是train,您可以將自己代碼中的啟動腳本命名為train,但我們更建議您使用我們提供的啟動腳本train,該腳本是基於Python的,可以幫助您解析傳入的超參數,並調用您代碼中的實際啟動腳本。
2.3 創建鏡像並上傳到Amazon ECR
在準備好Dockerfile和啟動腳本後,我們可以使用build_and_push.sh這個腳本創建鏡像並上傳到Amazon ECR。注意這個過程可能需要進行很多次,因為我們不可避免地要修改Dockerfile或者TensorFlow程序以使得它們可以正常工作。如果尚未調試完成,我們可以暫時不執行該腳本的最後一句docker push ${fullname},以避免頻繁上傳鏡像到Amazon ECR。
2.4 本地測試
在創建鏡像完成後,我們可以使用Amazon SageMaker的本地模式進行本地測試:第一步,執行utils/setup.sh來初始化本地模式。第二步,指定執行的角色,這裡我們假設您是在Amazon SageMaker Notebook上執行的,如果是其他環境,您可能需要手動指定角色的ARN。第三步,設定超參數,這裡需要對應到您程序中所需的超參數。第四步,設定訓練機型為local或者local_gpu(支持GPU)。第五步,創建Estimator,這裡需要傳入之前獲得的角色、訓練機型、機器數量、鏡像名稱、超參數等。第六步,啟動訓練,這裡需要傳入訓練數據的位置,在本地模式下,訓練數據的位置可以設置成本地路徑。
role = get_execution_role()
hyperparameters = {'task_name': 'ner', 'do_train': 'true', 'do_eval': 'true', 'data_dir': '/opt/ml/input/data/training', 'output_dir': '/opt/ml/model', 'vocab_file': './albert_config/vocab.txt', 'bert_config_file': './albert_base_zh/albert_config_base.json', _seq_length': 128, 'train_batch_size': 64, 'learning_rate': 2e-5, 'num_train_epochs': 1}
instance_type = 'local'
if subprocess.call('nvidia-smi') == 0:
instance_type = 'local_gpu'
estimator = Estimator(role=role,
train_instance_count=1,
train_instance_type=instance_type,
image_name='sagemaker-tf-albert-chinese-ner:latest',
hyperparameters=hyperparameters)
estimator.fit('file:///home/ec2-user/SageMaker/albert-chinese-ner/data/')
訓練啟動後,我們可以看到訓練的日誌輸出,以及監控本機的GPU、CPU、內存等的使用率等情況,以確認程序可以正常工作。
如果在此過程中需要進入正在運行的容器內調試,我們可以使用docker ps命令獲取當前正在運行的容器ID,並使用docker exec -it /bin/bash進入容器內進行調試。
2.5 Amazon SageMaker測試
在本地測試和上傳鏡像到Amazon ECR完成後,我們可以使用Amazon SageMaker進行測試:第一步,上傳數據到Amazon S3,獲取鏡像在Amazon ECR的地址。第二步,指定執行的角色,這裡我們假設您是在Amazon SageMaker Notebook上執行的,如果是其他環境,您可能需要手動指定角色的ARN。第三步,設定超參數,這裡需要對應到您程序中所需的超參數。第四步,設定訓練機型為ml.p2.xlarge(支持GPU)。第五步,創建Estimator,這裡需要傳入之前獲得的角色、訓練機型、機器數量、鏡像地址、超參數等。第六步,啟動訓練,這裡需要傳入訓練數據的位置,在Amazon SageMaker模式下,訓練數據的位置需要設置成Amazon S3路徑。
prefix = 'DEMO-tensorflow-albert-chinese-ner'
sess = sage.Session()
WORK_DIRECTORY = '/home/ec2-user/SageMaker/albert-chinese-ner/data'
data_location = sess.upload_data(WORK_DIRECTORY, key_prefix=prefix)
client = boto3.client('sts')
account = client.get_caller_identity()['Account']
my_session = boto3.session.Session()
region = my_session.region_name
algorithm_name = 'sagemaker-tf-albert-chinese-ner'
ecr_image = '{}.dkr.ecr.{}.amazonaws.com/{}:latest'.format(account, region, algorithm_name)
hyperparameters = {'task_name': 'ner', 'do_train': 'true', 'do_eval': 'true', 'data_dir': '/opt/ml/input/data/training', 'output_dir': '/opt/ml/model', 'vocab_file': './albert_config/vocab.txt', 'bert_config_file': './albert_base_zh/albert_config_base.json', 'max_seq_length': 128, 'train_batch_size': 64, 'learning_rate': 2e-5, 'num_train_epochs': 3}
instance_type = 'ml.p2.xlarge'
estimator = Estimator(role=role,
train_instance_count=1,
train_instance_type=instance_type,
image_name=ecr_image,
hyperparameters=hyperparameters)
estimator.fit(data_location)
訓練啟動後,我們可以在Amazon SageMaker控制臺看到這個訓練任務,點進詳情可以看到訓練的詳情,日誌輸出,以及監控機器的GPU、CPU、內存等的使用率等情況,以確認程序可以正常工作。
在此過程中我們無法進入正在運行的容器內調試,您可以將儘量多的日誌列印出來,或者輸出到/opt/ml/output路徑下,該路徑下的所有文件在訓練完成後會被自動打包成output.tar.gz放到設定好的位於Amazon S3的輸出路徑下。
2.6 訓練結果
本文所示程序使用了MSRA公開的中文實體識別數據集進行訓練,在訓練3輪之後,最優的F1值就可以達到0.948345,屬於比較領先的結果。
***** Eval results albert_base_ner_checkpoints/model.ckpt-0 *****
eval_f = 0.01672106
eval_precision = 0.010008455
eval_recall = 0.10698523
global_step = 0
loss = 2367.2935
***** Eval results albert_base_ner_checkpoints/model.ckpt-1000 *****
eval_f = 0.9256434
eval_precision = 0.95667034
eval_recall = 0.8976247
global_step = 1000
loss = 17.80814
***** Eval results albert_base_ner_checkpoints/model.ckpt-2000 *****
eval_f = 0.9444123
eval_precision = 0.94401
eval_recall = 0.9452899
global_step = 2000
loss = 10.842231
***** Eval results albert_base_ner_checkpoints/model.ckpt-2374 *****
eval_f = 0.948345
eval_precision = 0.9542561
eval_recall = 0.94261235
global_step = 2374
loss = 10.520088
3. 自定義腳本(BYOS)
使用BYOS的方法和BYOC的不同之處在於:BYOC是使用用戶自己創建的鏡像來運行程序,更適用於用戶對鏡像自定義程度較高的使用情景;而BYOS是使用預先構建好的鏡像,只是傳入用戶自己的代碼來運行程序,不需要用戶自己調試鏡像,更適用於比較簡單的使用情景。
由於不需要編譯自定義鏡像,我們可以直接進行本地測試和Amazon SageMaker測試,完整流程見
tensorflow_script_mode_quickstart.ipynb。
3.1 本地測試
我們可以使用Amazon SageMaker的本地模式進行本地測試:第一步,執行utils/setup.sh來初始化本地模式。第二步,指定執行的角色,這裡我們假設您是在Amazon SageMaker Notebook上執行的,如果是其他環境,您可能需要手動指定角色的ARN。第三步,設定超參數,這裡需要對應到您程序中所需的超參數。第四步,設定訓練機型為local或者local_gpu(支持GPU)。第五步,創建一個名為TensorFlow的Estimator,這裡需要傳入訓練入口腳本(entry_point)、原始碼路徑(source_dir)、之前獲得的角色、訓練機型、機器數量、TensorFlow版本、Python版本、超參數等。第六步,啟動訓練,這裡需要傳入訓練數據的位置,在本地模式下,訓練數據的位置可以設置成本地路徑。
role = get_execution_role()
hyperparameters = {'task_name': 'ner', 'do_train': 'true', 'do_eval': 'true', _dir': '/opt/ml/input/data/training', 'output_dir': '/opt/ml/model', 'vocab_file': './albert_config/vocab.txt', 'bert_config_file': './albert_base_zh/albert_config_base.json', _seq_length': 128, 'train_batch_size': 64, 'learning_rate': 2e-5, 'num_train_epochs': 1}
train_instance_type='local'
if subprocess.call('nvidia-smi') == 0:
train_instance_type = 'local_gpu'
estimator = TensorFlow(entry_point='albert_ner.py',
source_dir='.',
train_instance_type=train_instance_type,
train_instance_count=1,
hyperparameters=hyperparameters,
role=role,
framework_version='1.15.2',
py_version='py3',
script_mode=True)
inputs = {'training': f'file:///home/ec2-user/SageMaker/albert-chinese-ner/data/'}
estimator.fit(inputs)
這裡我們可以注意到estimator.fit()傳入的參數與BYOC略有不同,這兩個寫法其實是等價的,事實上,這裡的寫法更規範一些,按照Amazon SageMaker的文檔,輸入數據可以有多個通道(Channel),默認的通道是training,在本文的代碼中,訓練、驗證等過程其實都是從training通道中讀取的數據,所以更規範的做法是,我們應該額外增加一個通道validation,用來存放驗證數據。
訓練啟動後,我們可以看到訓練的日誌輸出,以及監控本機的GPU、CPU、內存等的使用率等情況,以確認程序可以正常工作。
如果在此過程中需要進入正在運行的容器內調試,我們可以使用docker ps命令獲取當前正在運行的容器ID,並使用docker exec -it /bin/bash進入容器內進行調試。另外,我們使用docker images命令可以看到Amazon SageMaker自動下載了一個名為
763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-training:1.15.2-gpu-py3的鏡像,該鏡像是由Amazon SageMaker預編譯的。
3.2 Amazon SageMaker測試
在本地測試完成後,我們可以使用Amazon SageMaker進行測試:第一步,上傳數據到Amazon S3。第二步,指定執行的角色,這裡我們假設您是在Amazon SageMaker Notebook上執行的,如果是其他環境,您可能需要手動指定角色的ARN。第三步,設定超參數,這裡需要對應到您程序中所需的超參數。第四步,設定訓練機型為ml.p2.xlarge(支持GPU)。第五步,創建一個名為TensorFlow的Estimator,這裡需要傳入訓練入口腳本(entry_point)、原始碼路徑(source_dir)、之前獲得的角色、訓練機型、機器數量、TensorFlow版本、Python版本、超參數等。第六步,啟動訓練,這裡需要傳入訓練數據的位置,在Amazon SageMaker模式下,訓練數據的位置需要設置成Amazon S3路徑。
inputs = sagemaker.Session().upload_data(path='/home/ec2-user/SageMaker/albert-chinese-ner/data', key_prefix='DEMO-tensorflow-albert-chinese-ner')
estimator = TensorFlow(entry_point='albert_ner.py',
source_dir='.',
train_instance_type='ml.p2.xlarge',
train_instance_count=1,
hyperparameters=hyperparameters,
role=role,
framework_version='1.15.2',
py_version='py3',
script_mode=True)
estimator.fit({'training': inputs})
訓練啟動後,我們可以在Amazon SageMaker控制臺看到這個訓練任務,點進詳情可以看到訓練的詳情,日誌輸出,以及監控機器的GPU、CPU、內存等的使用率等情況,以確認程序可以正常工作。
在這裡,source_dir我們設置的是本地代碼路徑,Amazon SageMaker會自動將該路徑下的所有代碼和數據拷貝進容器中。此外,BYOS模式還支持git路徑作為代碼路徑,使用方法如下:
git_config = {'repo': 'https://github.com/whn09/albert-chinese-ner.git', 'branch': 'master'}
estimator = TensorFlow(entry_point='albert_ner.py',
source_dir='.',
git_config=git_config,
train_instance_type='ml.p2.xlarge',
train_instance_count=1,
hyperparameters=hyperparameters,
role=role,
framework_version='1.15.2',
py_version='py3',
script_mode=True)
estimator.fit({'training': inputs})
但是,由於本文所用代碼需要ALBERT預訓練數據,而該數據不包含在git內,所以我們需要對代碼進行改造,以使得在代碼內下載並解壓數據,才能夠正常訓練。這裡我們不再展示如何操作,感興趣的讀者可以自行嘗試。
四、結論
本文講解了如何使用Amazon SageMaker運行基於TensorFlow的中文命名實體識別,其中算法部分是使用預訓練語言模型ALBERT做中文命名實體識別。
本文展示了如何把一個已有項目快速運行到Amazon SageMaker上,如果您想使用到Amazon SageMaker的更多高級用法,需要對已有項目進行改造,比如支持實時推理、批量推理、斷點重新訓練等,具體可以查看Amazon SageMaker的文檔。
本文所演示的使用方法是基於單機單卡的,Amazon SageMaker 提供基於 Docker 的簡化分布式 TensorFlow 訓練平臺,如果要將程序擴展到多機多卡進行訓練,可以參考其他相關博客。
本篇作者