本文首先以 DistilBERT 模型為基礎,針對二元分類別任務進行微調,設定訓練引數,包含學習率、批次大小、訓練迭代次數等,並利用 accuracy 函式計算模型準確度。透過訓練後的模型,對測試資料集進行預測,並將預測結果與真實標籤進行比較,最終獲得 94.58% 的準確率。接著,文章進一步探討如何將 BERT 模型應用於命名實體辨識(NER)任務。為此,匯入了 datasets、transformers 和 seqeval 等函式庫,並載入 ade_corpus_v2 資料集。由於資料集中存在部分句子重複但標註不同的情況,因此進行了資料預處理,將相同句子的標註資訊合併,避免模型混淆,為後續 NER 模型訓練做好準備。
步驟3:模型訓練
在這個步驟中,我們將設定一個根據BERT的模型進行微調和評估。首先,我們載入DistilBERT模型,如下所示:
from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
classification_model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased", num_labels=2)
內容解密:
這段程式碼初始化了我們的分類別模型。首先,我們從transformers函式庫中匯入必要的元件。然後,使用AutoModelForSequenceClassification建立classification_model。這個模型,特別是distilbert-base-uncased版本,是預先訓練並微呼叫於序列分類別任務的。我們指定num_labels=2,表示這是一個二元分類別任務。這一步驟為在我們準備好的資料集上訓練模型奠定了基礎。
接下來,我們將設定方法來評估模型。首先,我們匯入evaluate函式庫並載入準確度方法,如下所示:
import evaluate
accuracy = evaluate.load("accuracy")
內容解密:
這裡,我們使用evaluate函式庫來評估模型的效能。載入的accuracy方法將用於計算模型的準確度。
然後,我們定義一個方法來計算準確度,如下所示:
import numpy as np
def calculate_metrics(eval_pred):
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return accuracy.compute(predictions=predictions, references=labels)
內容解密:
這個程式碼區塊引入了calculate_metrics函式,這對於評估模型在測試集上的有效性至關重要。該函式從eval_pred中檢索預測和標籤。然後,利用NumPy來識別每個輸入的最可能的預測。最後,透過將這些預測與實際標籤進行比較來計算準確度。這種評估過程為我們提供了有關模型在未見資料上的優勢和劣勢的寶貴見解。
最後,讓我們微調DistilBERT模型,以分類別和預測句子是否與ADE相關,如下所示:
train_parameters = TrainingArguments(
output_dir="./results",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=16,
num_train_epochs=5,
weight_decay=0.01,
)
trainer = Trainer(
model=classification_model,
args=train_parameters,
train_dataset=tokenized_ade["train"],
eval_dataset=tokenized_ade["test"],
tokenizer=text_tokenizer,
data_collator=padding_collator,
compute_metrics=calculate_metrics,
)
trainer.train()
內容解密:
在這個程式碼區塊中,我們設定了訓練組態並啟動了模型的訓練。首先,我們使用TrainingArguments定義了train_parameters,指定了輸出目錄、學習率、批次大小、迭代次數和權重衰減。然後,我們建立了一個Trainer物件,提供我們的分類別模型、訓練引數、資料集、分詞器、資料整理器和自定義指標計算函式。最後,我們使用trainer.train()開始訓練模型。這個過程是我們的模型從資料中學習並適應以有效地執行分類別任務。
步驟4:模型評估
任何ML/NLP流程的最後一步都是在訓練後評估模型。但在評估模型之前,讓我們先用一個示例推斷來測試我們的模型在保留的測試資料集上的表現。讓我們從測試資料集中取出一個示例記錄,如下所示:
ade["test"][0]
{'text': '在吞嚥功能障礙和肺炎的患者中,應獲得礦物油使用的病史,如果發生了礦物油使用,則應在鑑別診斷中考慮ELP的診斷。', 'label': 1}
內容解密:
這裡,我們從測試資料集中提取了一個文字範例及其對應的標籤。
我們將使用transformers函式庫中的pipeline方法對這個示例記錄進行推斷,如下所示:
text = ade["test"][0]['text']
from transformers import pipeline
text_classifier = pipeline("text-classification", model="fine_tuned_classification_model")
text_classifier(text)
內容解密:
首先,我們提取測試資料集中的一個文字範例。然後,使用我們的微調模型初始化一個文字分類別pipeline,並呼叫這個pipeline對範例文字進行分類別,展示我們的模型在單個示例上的表現。微調模型傳回以下輸出:
[{'label': 'LABEL_1', 'score': 0.9991610050201416}]
這表明它以99.9%的信心度預測該記錄與ADE相關。
現在,我們可以對整個資料集執行此推斷,並將預測結果與實際標籤一起記錄在Pandas資料框中,如下所示:
from transformers import pipeline
import pandas as pd
# 載入微調後的分類別模型用於文字分類別
text_classifier = pipeline("text-classification", model="fine_tuned_classification_model")
# 假設您有 'ade[\"test\"]' 資料集
test_data = ade["test"]
內容解密:
這段程式碼將我們的微調模型應用於整個測試資料集,並將結果儲存在Pandas資料框中,以便進一步分析和評估模型的效能。
微調BERT模型進行句子分類別與命名實體辨識的實踐
在前面的章節中,我們成功地對根據BERT的模型(特別是DistilBERT變體)進行了微調,以執行句子分類別任務,取得了94.58%的顯著準確率。本章節將在此基礎上進一步探討如何對BERT模型進行微調,以執行更複雜的命名實體辨識(NER)任務。
句子分類別任務的評估與結果
首先,我們使用微調後的分類別模型對ade["test"]資料集進行評估。以下為評估過程的程式碼:
# 建立空列表以儲存結果
texts = []
true_labels = []
predicted_labels = []
# 迭代測試資料集中的每個記錄
for record in test_data:
text = record["text"]
true_label = record["label"]
# 使用文字分類別器進行預測
prediction = text_classifier(text)
predicted_label = prediction[0]["label"]
# 將結果附加到列表中
texts.append(text)
true_labels.append(true_label)
predicted_labels.append(predicted_label)
# 建立DataFrame以顯示結果
evaluation_results = pd.DataFrame({
"Text": texts,
"True Label": true_labels,
"Predicted Label": predicted_labels
})
# 列印DataFrame
print(evaluation_results)
內容解密:
- 迭代測試資料集:遍歷測試資料集中的每個文字記錄。
- 文字分類別:使用微調後的模型對每個文字進行分類別預測。
- 結果儲存:將原始文字、真實標籤和預測標籤儲存到列表中。
- DataFrame建立:將結果整理成Pandas DataFrame,以便清晰地檢視和分析模型的預測結果。
接著,我們計算模型的準確率:
# 將預測標籤對映為數值格式
evaluation_results['Predicted Label'] = evaluation_results['Predicted Label'].map({"LABEL_0": 0, "LABEL_1": 1})
# 將真實標籤轉換為整數型別
evaluation_results['True Label'] = evaluation_results['True Label'].astype(int)
# 計算準確率
correct_predictions = (evaluation_results['True Label'] == evaluation_results['Predicted Label']).sum()
total_samples = len(evaluation_results)
accuracy = correct_predictions / total_samples
# 列印準確率
print(f"Accuracy: {accuracy:.2%}")
# 將評估結果儲存為CSV檔案
evaluation_results.to_csv("accuracy_results.csv", index=False)
內容解密:
- 標籤對映:將預測標籤從文字格式轉換為數值格式(0和1)。
- 準確率計算:比較真實標籤和預測標籤,計算正確預測的比例。
- 結果儲存:將評估結果儲存為CSV檔案,以便進一步分析。
最終輸出結果顯示模型的準確率為94.58%,證明瞭我們的微調方法的有效性。
微調BERT模型進行命名實體辨識
下一步,我們將探索如何對BERT模型進行微調,以進行命名實體辨識(NER)任務。我們將使用在科學和生物醫學資料集上預訓練的BERT變體,以更好地理解醫學文字中的複雜詞彙。
首先,我們安裝必要的Python函式庫:
!pip install datasets transformers seqeval
!pip install accelerate -U
內容解密:
- 安裝資料處理函式庫:
datasets函式庫用於處理資料,transformers函式庫提供強大的NLP模型,seqeval函式庫用於評估NER任務。 - 更新加速函式庫:
accelerate函式庫的更新有助於提高模型在不同硬體平台上的訓練效率。
本章節展示瞭如何系統地對BERT模型進行微調,以應對句子分類別和命名實體辨識等NLP任務。透過仔細的資料準備、模型選擇和評估,我們成功地實作了高準確率的模型,為未來的NLP應用奠定了堅實的基礎。
匯入必要的函式庫與模組
在進行命名實體辨識(NER)任務之前,我們首先需要匯入一系列的函式庫與模組。這些工具將幫助我們高效地處理、訓練和評估NER模型。
from datasets import Dataset, ClassLabel, Sequence, load_dataset, load_metric
import numpy as np
import pandas as pd
from spacy import displacy
import transformers
from transformers import (AutoModelForTokenClassification,
AutoTokenizer,
DataCollatorForTokenClassification,
pipeline,
TrainingArguments,
Trainer)
內容解密:
- datasets 函式庫:用於載入和管理資料集,提供多種功能如資料集載入、指標計算和資料型別處理。
- numpy 和 pandas:用於數值運算和資料框操作,是資料處理的基礎工具。
- SpaCy 的 displacy:用於視覺化命名實體辨識的結果,幫助理解模型的輸出。
- transformers 函式庫:提供了多種預訓練模型和工具,如
AutoModelForTokenClassification和AutoTokenizer,用於模型和分詞器的設定。 DataCollatorForTokenClassification:用於資料準備,將資料整理成模型所需的格式。pipeline:提供簡便的推理介面,可以快速進行預測。Trainer和TrainingArguments:用於模型的訓練和組態,簡化訓練流程。
載入資料集
接下來,我們載入 ade_corpus_v2 資料集中的 Ade_corpus_v2_drug_ade_relation 子集,用於後續的處理和分析。
datasets = load_dataset("ade_corpus_v2", "Ade_corpus_v2_drug_ade_relation")
內容解密:
load_dataset函式:從 Hugging Face 的資料集函式庫中載入指定的資料集。ade_corpus_v2:一個用於藥物不良反應(ADE)研究的資料集,包含文字、藥物、效果及其索引資訊。
資料集範例
以下是資料集中的一個範例記錄:
{'text': 'Intravenous azithromycin-induced ototoxicity.',
'drug': 'azithromycin',
'effect': 'ototoxicity',
'indexes': {'drug': {'start_char': [12], 'end_char': [24]},
'effect': {'start_char': [33], 'end_char': [44]}}}
內容解密:
text:原始文字,描述了一個藥物不良反應事件。drug和effect:分別表示藥物名稱和不良反應。indexes:提供了藥物和不良反應在文字中的起始和結束字元索引。
資料預處理
在進行模型訓練之前,我們需要對資料進行預處理。觀察資料集後發現,部分句子重複出現,但標註的藥物和不良反應不同。
重複句子的問題
重複的句子會導致相同的詞彙在不同的標註中出現,從而引起模型混淆。因此,我們需要合併這些重複句子的標註資訊。
merged_dataset = {}
for item in datasets["train"]:
text = item["text"]
if text not in merged_dataset:
merged_dataset[text] = {
"text": text,
"drugs": [item["drug"]],
"effects": [item["effect"]],
"drug_starts": set(item["indexes"]["drug"]["start_char"]),
"drug_ends": set(item["indexes"]["drug"]["end_char"]),
"effect_starts": set(item["indexes"]["effect"]["start_char"]),
"effect_ends": set(item["indexes"]["effect"]["end_char"])
}
else:
merged_data = merged_dataset[text]
merged_data["drugs"].append(item["drug"])
merged_data["effects"].append(item["effect"])
merged_data["drug_starts"].update(item["indexes"]["drug"]["start_char"])
merged_data["drug_ends"].update(item["indexes"]["drug"]["end_char"])
merged_data["effect_starts"].update(item["indexes"]["effect"]["start_char"])
merged_data["effect_ends"].update(item["indexes"]["effect"]["end_char"])
內容解密:
merged_dataset:一個字典,用於儲存合併後的資料。- 迴圈遍歷:對訓練資料集中的每一項進行處理,合併相同文字的不同標註資訊。
drug_starts和drug_ends:集合,用於儲存藥物名稱的起始和結束字元索引,同樣適用於不良反應。- 更新合併資料:將新的標註資訊加入到已存在的文字記錄中。
透過上述步驟,我們成功地對資料進行了預處理,為後續的模型訓練做好了準備。