2018年google推出了bert模型,這個模型的性能要遠超於之前所使用的模型,總的來講就是很牛。可是訓練bert模型是異常昂貴的,對於通常人來講並不須要本身單獨訓練bert,只須要加載預訓練模型,就能夠完成相應的任務。下面我將以情感分類爲例,介紹使用bert的方法。這裏與咱們以前調用API寫代碼有所區別,已經有大神將bert封裝成.py文件,咱們只須要簡單修改一下,就能夠直接調用這些.py文件了。python
我這裏使用的是pytorch版本。git
不管是tf版仍是pytorch版本,預訓練模型都須要三個文件(或者功能相似的)github
文檔裏提供了convert_tf_checkpoint_to_pytorch.py 這個腳原本進行模型轉換。使用方法以下:shell
export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12 pytorch_pretrained_bert convert_tf_checkpoint_to_pytorch \ $BERT_BASE_DIR/bert_model.ckpt \ $BERT_BASE_DIR/bert_config.json \ $BERT_BASE_DIR/pytorch_model.bin
這裏是須要實現情感分類。只須要用到run_classifier_dataset_utils.py和run_classifier.py這兩個文件。run_classifier_dataset_utils.py是用來處理文本的輸入,咱們只須要添加一個類用來處理輸入便可。json
class MyProcessor(DataProcessor): '''Processor for the sentiment classification data set''' def get_train_examples(self, data_dir): """See base class.""" logger.info("LOOKING AT {}".format(os.path.join(data_dir, "train.tsv"))) return self._create_examples( self._read_tsv(os.path.join(data_dir, "train.tsv")), "train") def get_dev_examples(self, data_dir): """See base class.""" return self._create_examples( self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev") def get_labels(self): """See base class.""" return ["-1", "1"] def _create_examples(self, lines, set_type): """Creates examples for the training and dev sets.""" examples = [] for (i, line) in enumerate(lines): if i == 0: continue guid = "%s-%s" % (set_type, i) text_a = line[0] label = line[1] examples.append( InputExample(guid=guid, text_a=text_a, text_b=None, label=label)) return examples
train.tsv和dev.tsv分別表示訓練集和測試集。記得要在下面的代碼加上以前定義的類。bash
def compute_metrics(task_name, preds, labels): assert len(preds) == len(labels) if task_name == "cola": return {"mcc": matthews_corrcoef(labels, preds)} elif task_name == "sst-2": return {"acc": simple_accuracy(preds, labels)} elif task_name == "mrpc": return acc_and_f1(preds, labels) elif task_name == "sts-b": return pearson_and_spearman(preds, labels) elif task_name == "qqp": return acc_and_f1(preds, labels) elif task_name == "mnli": return {"acc": simple_accuracy(preds, labels)} elif task_name == "mnli-mm": return {"acc": simple_accuracy(preds, labels)} elif task_name == "qnli": return {"acc": simple_accuracy(preds, labels)} elif task_name == "rte": return {"acc": simple_accuracy(preds, labels)} elif task_name == "wnli": return {"acc": simple_accuracy(preds, labels)} elif task_name == "my": return acc_and_f1(preds, labels) else: raise KeyError(task_name) processors = { "cola": ColaProcessor, "mnli": MnliProcessor, "mnli-mm": MnliMismatchedProcessor, "mrpc": MrpcProcessor, "sst-2": Sst2Processor, "sts-b": StsbProcessor, "qqp": QqpProcessor, "qnli": QnliProcessor, "rte": RteProcessor, "wnli": WnliProcessor, "my": MyProcessor } output_modes = { "cola": "classification", "mnli": "classification", "mrpc": "classification", "sst-2": "classification", "sts-b": "regression", "qqp": "classification", "qnli": "classification", "rte": "classification", "wnli": "classification", "my": "classification" }
編輯shell腳本:app
#!/bin/bash export TASK_NAME=my python run_classifier.py \ --task_name $TASK_NAME \ --do_train \ --do_eval \ --do_lower_case \ --data_dir /home/garvey/Yuqinfenxi/ \ --bert_model /home/garvey/uncased_L-12_H-768_A-12 \ --max_seq_length 410 \ --train_batch_size 8 \ --learning_rate 2e-5 \ --num_train_epochs 3.0 \ --output_dir /home/garvey/bertmodel
運行便可。這裏要注意max_seq_length和train_batch_size這兩個參數,設置過大是很容易爆掉顯存的,通常來講運行bert須要11G左右的顯存。性能
max_seq_length是指詞的數量而不是指字符的數量。參考代碼中的註釋:學習
The maximum total input sequence length after WordPiece tokenization. Sequences longer than this will be truncated, and sequences shorter than this will be padded.測試
對於sequence的理解,網上不少博客都把這個翻譯爲句子,我我的認爲是不許確的,序列是能夠包含多個句子的,而不僅是單獨一個句子。
Bert開源的代碼中,只提供了train和dev數據,也就是訓練集和驗證集。對於評測論文標準數據集的時候,只須要把訓練集和測試集送進去就能夠獲得結果,這一過程是沒有調參的(沒有驗證集),都是使用默認參數。可是若是用Bert來打比賽,注意這個時候的測試集是沒有標籤的,這就須要在源碼中加上一個處理test數據集的部分,而且經過驗證集來選擇參數。
在大的預訓練模型例如像bert-large在對小的訓練集進行精細調整的時候,每每會致使性能退化:模型要麼運行良好,要麼根本不起做用,在咱們用bert-large對一些小數據集進行微調,直接使用默認參數的話二分類的準確率只有0.5,也就是一點做用也沒有,這個時候須要對學習率和迭代次數進行一個調整纔會有一個正常的結果,這個問題暫時尚未獲得解決。