Paddle加載NLP的各類預訓練模型方法總結(以文本分類任務爲例,包含完整代碼)

一、Introduction

最近宅在家,有空只能搞搞NLP的比賽。由於缺乏GPU的加持,只好白嫖百度的AI Studio(畢竟人家提供免費的Tesla V100)。在此不得不讚揚一下優秀的國產深度學習框架–Paddle(飛漿),代碼精煉,使用簡單,具有極高的集成度,非常適合初學者上手。
由於代碼中用到了各種預訓練模型做遷移學習,所以在此記錄一下Paddle Hub加載各類預訓練模型的方法。

二、Method

使用Paddle進行訓練大概分爲以下幾個步驟:

  • 加載預訓練模型
  • 加載數據集
  • 生成reader
  • 選擇Fine-Tune優化策略
  • 選擇運行配置
  • 組建Fine-Tune任務
  • 開始Fine-Tune
  1. 加載預訓練模型

    首先需要在命令行更新paddlehub到最新版本:
    pip install --upgrade paddlehub -i https://pypi.tuna.tsinghua.edu.cn/simple
    然後通過下面的語法進行預訓練模型的加載(若本地未找到會自動聯網下載且不限速)

    import paddlehub as hub
    module = hub.Module(name="ernie")
    

    一些常用的NLP預訓練模型如下表所示:

模型名 PaddleHub Module
ERNIE, Chinese hub.Module(name=‘ernie’)
ERNIE 2.0 Tiny, Chinese hub.Module(name=‘ernie_tiny’)
ERNIE 2.0 Base, English hub.Module(name=‘ernie_v2_eng_base’)
ERNIE 2.0 Large, English hub.Module(name=‘ernie_v2_eng_large’)
RoBERTa-Large, Chinese hub.Module(name=‘roberta_wwm_ext_chinese_L-24_H-1024_A-16’)
RoBERTa-Base, Chinese hub.Module(name=‘roberta_wwm_ext_chinese_L-12_H-768_A-12’)
BERT-Base, Uncased hub.Module(name=‘bert_uncased_L-12_H-768_A-12’)
BERT-Large, Uncased hub.Module(name=‘bert_uncased_L-24_H-1024_A-16’)
BERT-Base, Cased hub.Module(name=‘bert_cased_L-12_H-768_A-12’)
BERT-Large, Cased hub.Module(name=‘bert_cased_L-24_H-1024_A-16’)
BERT-Base, Multilingual Cased hub.Module(nane=‘bert_multi_cased_L-12_H-768_A-12’)
BERT-Base, Chinese hub.Module(name=‘bert_chinese_L-12_H-768_A-12’)
  1. 準備Dataset
    下面是自定義數據集的寫法,輸入的file需要以文本\t標籤的格式保存。

    from paddlehub.dataset.base_nlp_dataset import BaseNLPDataset
     
    class DemoDataset(BaseNLPDataset):
        """DemoDataset"""
        def __init__(self):
            # 數據集存放位置
            self.dataset_dir = "path/to/dataset"
            super(DemoDataset, self).__init__(
                base_path=self.dataset_dir,
                train_file="train.tsv",
                dev_file="dev.tsv",
                test_file="test.tsv",
                # 如果還有預測數據(不需要文本類別label),可以放在predict.tsv
                predict_file="predict.tsv",
                train_file_with_header=True,
                dev_file_with_header=True,
                test_file_with_header=True,
                predict_file_with_header=True,
                # 數據集類別集合
                label_list=["0", "1"])
    dataset = DemoDataset()
    
  2. 生成Reader
    接着生成一個reader,以文本分類任務爲例,reader負責將dataset的數據進行預處理,首先對文本進行分詞,然後以特定格式組織並輸入給模型進行訓練。

    ClassifyReader的參數有三個:

    • dataset: 傳入PaddleHub Dataset;
    • vocab_path: 傳入ERNIE/BERT模型對應的詞表文件路徑;
    • max_seq_len: ERNIE模型的最大序列長度,若序列長度不足,會通過padding方式補到max_seq_len, 若序列長度大於該值,則會以截斷方式讓序列長度爲max_seq_len;
    reader = hub.reader.ClassifyReader(
        dataset=dataset,
        vocab_path=module.get_vocab_path(),
        sp_model_path=module.get_spm_path(),
        word_dict_path=module.get_word_dict_path(),
        max_seq_len=128)
    
  3. 選擇Fine-Tune優化策略
    對於ERNIE/BERT這類Transformer模型來說最合適的遷移優化策略就是AdamWeightDecayStrategy了。

    AdamWeightDecayStrategy的參數有三個:

    • learning_rate: 最大學習率
    • lr_scheduler: 有linear_decay和noam_decay兩種衰減策略可選
    • warmup_proprotion: 訓練預熱的比例,若設置爲0.1, 則會在前10%的訓練step中學習率逐步提升到learning_rate
    • weight_decay: 權重衰減,類似模型正則項策略,避免模型overfitting
    • optimizer_name: 優化器名稱,推薦使用Adam
    strategy = hub.AdamWeightDecayStrategy(
        weight_decay=0.01,
        warmup_proportion=0.1,
        learning_rate=5e-5)
    

    PaddleHub還額外提供了多個優化策略,如AdamWeightDecayStrategy、ULMFiTStrategy、DefaultFinetuneStrategy等,詳細參數說明請移步官方文檔。

  4. 運行配置
    在進行Finetune前,我們可以設置一些運行時的配置。

    • use_cuda:設置爲False表示使用CPU進行訓練。如果您本機支持GPU,且安裝的是GPU版本的PaddlePaddle,我們建議您將這個選項設置爲True
    • epoch:要求Finetune的任務只遍歷1次訓練集
    • batch_size:每次訓練的時候,給模型輸入的每批數據大小爲32,模型訓練時能夠並行處理批數據,因此batch_size越大,訓練的效率越高,但是同時帶來了內存的負荷,過大的batch_size可能導致內存不足而無法訓練,因此選擇一個合適的batch_size是很重要的一步
    • log_interval:每隔10 步打印一次訓練日誌
    • eval_interval:每隔50 步在驗證集上進行一次性能評估
    • checkpoint_dir:將訓練的參數和數據保存到model文件夾下
    • strategy:使用DefaultFinetuneStrategy策略進行finetune
    config = hub.RunConfig(
    	use_cuda=True,
    	num_epoch=5,
    	checkpoint_dir="model",
    	batch_size=100,
    	eval_interval=50,
    	strategy=strategy)
    
  5. 組建Fine-Tune任務
    有了合適的預訓練模型和準備要遷移的數據集後,我們開始組建一個Task。

    • 獲取module的上下文環境,包括輸入和輸出的變量,以及Paddle Program;
    • 從輸出變量中找到用於情感分類的文本特徵pooled_output;
    • 在pooled_output後面接入一個全連接層,生成Task;
    inputs, outputs, program = module.context(
    trainable=True, max_seq_len=128)
    
    # Use "pooled_output" for classification tasks on an entire sentence.
    pooled_output = outputs["pooled_output"]
    
    feed_list = [
        inputs["input_ids"].name,
        inputs["position_ids"].name,
        inputs["segment_ids"].name,
        inputs["input_mask"].name,
    ]
    
    cls_task = hub.TextClassifierTask(
        data_reader=reader,
        feature=pooled_output,
        feed_list=feed_list,
        num_classes=dataset.num_labels,
        config=config)
    
  6. 開始Fine-Tune
    我們通過finetune_and_eval接口來進行模型訓練。這個接口在finetune的過程中會週期性的進行模型效果的評估,以便我們瞭解整個訓練過程的性能變化。

    run_states = cls_task.finetune_and_eval()
    
  7. 模型預測

    import numpy as np
    
    # 寫入預測的文本數據
    data = [
        ["抗擊新型肺炎第一線中國加油鶴崗・綏濱縣"],["正能量青年演員朱一龍先生一起武漢祈福武漢加油中國加油"]]
    index = 0
    run_states = cls_task.predict(data=data)
    results = [run_state.run_results for run_state in run_states]
    for batch_result in results:
        # 獲取預測的標籤索引
        batch_result = np.argmax(batch_result, axis=2)[0]
        for result in batch_result:
            print("%s\預測值=%s" % (data[index][0], result))
            index += 1
    

三、Conclusion

本次文章簡單介紹了以文本分類任務爲例的paddle框架做預訓練模型加載和微調的過程。這種新一代的國產框架確實有很多亮點,值得我們去學習與探索。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章