基于 LlamaFactory 微調(diào)大模型的實體識別的評估實現(xiàn)
介紹
使用 LlamaFactory 結(jié)合開源大語言模型實現(xiàn)文本分類:從數(shù)據(jù)集構(gòu)建到 LoRA 微調(diào)與推理評估.https://blog.csdn.net/sjxgghg/article/details/144290200
在前一篇文章的文本分類評估中,已經(jīng)介紹了主要的框架,故在大模型微調(diào)的流程框架方面本文不再贅述。
實體數(shù)據(jù)集格式
下述是實體識別評估的一條數(shù)據(jù)示例:
{
"prompt": "從以下政府文本中,提取指定的實體類別,并按照JSON格式輸出結(jié)果。 xxx",
"predict": "\n```json\n{\n \"行政區(qū)劃和地理實體\": [],\n \"政府機構(gòu)和組織\": [],\n ... \"特定術(shù)語和關(guān)鍵詞\": [\"改革創(chuàng)新\", \"體制機制障礙\", \"行政管理體制\", \"城鄉(xiāng)一體化發(fā)展機制\"]\n}\n```",
"label": "```json\n{\n \"行政區(qū)劃和地理實體\": [],\n \"政府機構(gòu)和組織\": [], ... \"特定術(shù)語和關(guān)鍵詞\": [\"改革創(chuàng)新發(fā)展\", \"高質(zhì)量發(fā)展\", \"高品質(zhì)生活\", \"體制機制障礙\"]\n}\n```"
...
}
讓大模型按照json格式輸出。字典的鍵是實體的類別名,字典的值是一個列表其中包含所有該類別的所有預測結(jié)果。
實體識別評估代碼
import os
import re
import json
from dataclasses import dataclass
@dataclass
class EvalNode:
# 默認值
predict_right_num: int = 0
predict_num: int = 0
label_num: int = 0
@property
def accuracy(self):
return self.predict_right_num / (self.predict_num + 1e-6)
@property
def recall(self):
return self.predict_right_num / (self.label_num + 1e-6)
@property
def f1(self):
return 2 * self.accuracy * self.recall / (self.accuracy + self.recall + 1e-6)
@dataclass
class NEREvaluate:
ent_class: list[str]
input_file: str
avg_accuracy: int = 0
avg_recall: int = 0
avg_f1: int = 0
predict_error: int = 0
def __post_init__(self):
self._evaluate_by_jsonl()
def _evaluate_by_jsonl(self):
with open(self.input_file, "r", encoding="utf-8") as f:
self.total_ent = {ent: EvalNode() for ent in self.ent_class}
for line in f:
data = json.loads(line)
# 大模型采取的是序列到序列到文本生成,不能轉(zhuǎn)換為字典的數(shù)據(jù)跳過即可
try:
matches = re.search("\{.*?\}", data["predict"], re.DOTALL)
if matches:
predict = eval(matches.group(0))
except:
self.predict_error += 1
predict = {ent: [] for ent in self.ent_class}
try:
# 防止label出錯
matches = re.search("\{.*?\}", data["label"], re.DOTALL)
if matches:
labels = eval(matches.group(0))
except:
continue
# 每個不同的實體類別單獨計數(shù)
for ent_name in self.ent_class:
label_set = set(labels.get(ent_name, []))
predict_set = set(predict.get(ent_name, []))
self.total_ent[ent_name].predict_right_num += len(
label_set & predict_set
)
self.total_ent[ent_name].predict_num += len(predict_set)
self.total_ent[ent_name].label_num += len(label_set)
for ent in self.ent_class:
self.avg_accuracy += self.total_ent[ent].accuracy
self.avg_recall += self.total_ent[ent].recall
self.avg_f1 += self.total_ent[ent].f1
self.avg_accuracy = self.avg_accuracy / len(self.ent_class)
self.avg_recall = self.avg_recall / len(self.ent_class)
self.avg_f1 = self.avg_f1 / len(self.ent_class)
下述是實體的類別:
ENT_CLASS = [
"行政區(qū)劃和地理實體",
"政府機構(gòu)和組織",
"法律法規(guī)與政策",
"人物與職務",
"產(chǎn)業(yè)",
"產(chǎn)業(yè)園區(qū)",
"高新技術(shù)",
"項目與工程",
"社會服務與基礎設施",
"特定術(shù)語和關(guān)鍵詞",
]
ner_eval = NEREvaluate(
ENT_CLASS, "xxx/generated_predictions.jsonl")
)
for key, item in ner_eval.total_ent.items():
print(key, item.f1)
輸出評估結(jié)果:
行政區(qū)劃和地理實體 0.6292412411907403
人物與職務 0.45714235316380664
...
特定術(shù)語和關(guān)鍵詞 0.29256472295174
accuracy 、recall 與 f1 均進行了計算,大家參考代碼自行查看與輸出即可。
在評估大模型生成的實體時,只有大模型把實體的邊界完全預測正確,才認為預測對。
本文轉(zhuǎn)載自 ??AI悠閑區(qū)??,作者: jieshenai
贊
收藏
回復
分享
微博
QQ
微信
舉報

回復
相關(guān)推薦