随机场模型与命名实体识别:深入理解CRF及其应用

news2024/11/22 10:44:39

💗💗💗欢迎来到我的博客,你将找到有关如何使用技术解决问题的文章,也会找到某个技术的学习路线。无论你是何种职业,我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章,也欢迎在文章下方留下你的评论和反馈。我期待着与你分享知识、互相学习和建立一个积极的社区。谢谢你的光临,让我们一起踏上这个知识之旅!
请添加图片描述

文章目录

  • 🍋1. 条件随机场(CRF)概述
    • 🍋1.1 CRF模型的背景
    • 🍋1.2 CRF的数学表示
  • 🍋2. CRF在命名实体识别中的应用
    • 🍋2.1 使用CRF进行NER
  • 🍋3. 主流命名实体识别框架
    • 🍋3.1 BERT-CRF
    • 🍋3.2 LSTM-CRF
  • 🍋4. 代码实现
    • 🍋4.1 数据准备
    • 🍋4.2 LSTM-CRF模型
    • 🍋4.3 训练与评估
  • 🍋5. 使用CRF进行处理Resume数据集
  • 🍋6. 总结

命名实体识别(Named Entity Recognition,简称NER)是自然语言处理中的一项重要任务,它涉及从文本中识别出具有特定意义的实体,如人名、地点、时间、机构等。为了解决NER问题,许多机器学习和深度学习模型都被提出,其中条件随机场(Conditional Random Field,简称CRF)是一种重要的模型。本文将从CRF的概念、应用领域以及在命名实体识别中的使用出发,介绍一些流行的命名实体识别框架,如BERT-CRF和LSTM-CRF,最后展示具体的代码实现。

🍋1. 条件随机场(CRF)概述

🍋1.1 CRF模型的背景

随机场(Random Fields)是一种用于建模具有一定关联性的随机变量集合的概率模型。条件随机场(CRF)是图模型的一种,它是在给定观测序列的条件下,通过学习标签序列之间的条件概率分布来进行预测。与传统的隐马尔可夫模型(HMM)不同,CRF不仅考虑当前状态的转移概率,还能够建模任意的上下文信息。

🍋1.2 CRF的数学表示

在CRF中,我们有一个观测序列X=(x1,x2,x3,…,xn)和一个标签序列Y=(y1,y2,y3,…,yn),我们的目标是计算给定观测序列 X下标签序列Y的条件概率 P(Y∣X)
CRF的核心思想是通过最大化条件概率来进行模型训练:

在这里插入图片描述
其中,𝑓𝑘 是特征函数,𝜆𝑘 是特征函数的权重,Z(X) 是规范化常数,确保所有可能的标签序列的概率和为1。

🍋2. CRF在命名实体识别中的应用

命名实体识别的目标是从文本中提取出具有特定含义的实体。典型的NER任务包括识别人名、地点、组织、时间等信息。在NER中,输入是一个单词序列,而输出是每个单词的类别标签。

例如,给定句子:“Steve Jobs was born in San Francisco.”,NER的目标是为每个词汇分配一个标签(例如,PER表示人名,LOC表示地点名):

Steve    PER
Jobs     PER
was      O
born     O
in       O
San      LOC
Francisco LOC
.        O

🍋2.1 使用CRF进行NER

在命名实体识别中,CRF模型可以通过利用上下文信息来预测每个词的标签。CRF能够很好地建模标签之间的依赖关系,尤其是在标签是有序的(例如,连续的实体可能属于相同类别)时,CRF表现尤为出色。通过设计合适的特征函数,CRF能够综合考虑词本身的特征以及词之间的上下文关系,从而提高NER任务的准确率。

🍋3. 主流命名实体识别框架

🍋3.1 BERT-CRF

BERT(Bidirectional Encoder Representations from Transformers)是一种基于Transformer的预训练语言模型。由于BERT能够捕捉到上下文信息,并且支持双向编码,它在多项NLP任务中都表现出色,尤其在NER任务上,BERT取得了突破性的成果。

BERT-CRF结合了BERT模型的上下文表示能力与CRF的标签依赖建模能力。BERT负责提取每个词的上下文特征,而CRF则负责建模词之间的标签依赖关系,从而进一步提高命名实体识别的效果。

BERT-CRF的实现思路:

  • 使用BERT提取每个词的上下文表示。
  • 将BERT的输出作为CRF模型的输入。
  • 使用CRF层进行标签预测。

🍋3.2 LSTM-CRF

LSTM(Long Short-Term Memory)是一种常用的循环神经网络(RNN)模型,它在处理序列数据时具有较好的记忆能力。LSTM-CRF结合了LSTM模型的序列建模能力与CRF的标签依赖建模能力。

LSTM-CRF的实现思路:

  • 使用LSTM处理输入的词序列,生成每个词的隐藏状态表示。
  • 将LSTM的输出作为CRF模型的输入。
  • 使用CRF层进行标签预测。

LSTM-CRF对于长距离依赖关系的建模能力较强,尤其适用于需要考虑长期上下文信息的NER任务。

🍋4. 代码实现

🍋4.1 数据准备

在实现NER模型之前,我们需要准备好数据集。这里我们假设已经有一个预处理好的NER数据集,其中每个句子的每个词都对应着一个标签。

import torch
import torch.nn as nn
from torchcrf import CRF
from torch.utils.data import DataLoader, Dataset

# 示例数据集
class NERDataset(Dataset):
    def __init__(self, sentences, labels):
        self.sentences = sentences
        self.labels = labels

    def __len__(self):
        return len(self.sentences)

    def __getitem__(self, idx):
        return torch.tensor(self.sentences[idx]), torch.tensor(self.labels[idx])

# 假设已将数据预处理成了ID的形式
train_sentences = [[1, 2, 3], [4, 5, 6]]
train_labels = [[0, 1, 2], [0, 2, 1]]
train_data = NERDataset(train_sentences, train_labels)
train_loader = DataLoader(train_data, batch_size=2, shuffle=True)

🍋4.2 LSTM-CRF模型

LSTM-CRF模型的核心由LSTM层和CRF层构成。LSTM层负责处理输入序列的上下文信息,CRF层则处理标签之间的依赖关系。

class LSTMCRF(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, tagset_size):
        super(LSTMCRF, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, tagset_size)
        self.crf = CRF(tagset_size, batch_first=True)

    def forward(self, sentences, labels=None):
        embeddings = self.embedding(sentences)
        lstm_out, _ = self.lstm(embeddings)
        emissions = self.fc(lstm_out)
        if labels is not None:
            loss = -self.crf(emissions, labels)
            return loss
        else:
            return self.crf.decode(emissions)

🍋4.3 训练与评估

训练LSTM-CRF模型时,我们需要定义损失函数和优化器。训练过程中,我们通过计算模型的损失来更新参数。

# 模型实例化
model = LSTMCRF(vocab_size=10, embedding_dim=50, hidden_dim=128, tagset_size=3)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 训练过程
for epoch in range(10):
    model.train()
    total_loss = 0
    for sentences, labels in train_loader:
        optimizer.zero_grad()
        loss = model(sentences, labels)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f'Epoch {epoch}, Loss: {total_loss / len(train_loader)}')

🍋5. 使用CRF进行处理Resume数据集

import sklearn_crfsuite
from sklearn.model_selection import train_test_split
from sklearn_crfsuite import metrics

# 读取数据并进行处理
def read_data(file_path):
    sentences = []
    labels = []
    with open(file_path, 'r', encoding='utf-8') as f:
        sentence = []
        label = []
        for line in f:
            line = line.strip()
            if line:  # 非空行
                word, tag = line.split()  # 分割字符和标签
                sentence.append(word)
                label.append(tag)
            else:  # 空行表示一个句子的结束
                if sentence:
                    sentences.append(sentence)
                    labels.append(label)
                sentence = []
                label = []
        # 如果文件没有以空行结束,需要加上最后一个句子
        if sentence:
            sentences.append(sentence)
            labels.append(label)
    return sentences, labels

# 特征提取函数
def word2features(sentence, i):
    word = sentence[i]
    features = {
        'word.lower()': word.lower(),
        'word[-3:]': word[-3:],
        'word[-2:]': word[-2:],
        'is_first': i == 0,
        'is_last': i == len(sentence)-1,
        'prev_word': '' if i == 0 else sentence[i-1],
        'next_word': '' if i == len(sentence)-1 else sentence[i+1],
    }
    return features

# 转换为 CRF 格式
def prepare_data(sentences, labels):
    X = []
    y = []
    for sentence, label in zip(sentences, labels):
        X.append([word2features(sentence, i) for i in range(len(sentence))])
        y.append(label)
    return X, y

# 读取文件
train_sentences, train_labels = read_data('./data/ResumeNER/demo.train.char.bmes')
dev_sentences, dev_labels = read_data('./data/ResumeNER/demo.dev.char.bmes')
test_sentences, test_labels = read_data('./data/ResumeNER/demo.test.char.bmes')

# 准备特征
X_train, y_train = prepare_data(train_sentences, train_labels)
X_dev, y_dev = prepare_data(dev_sentences, dev_labels)
X_test, y_test = prepare_data(test_sentences, test_labels)

# 训练 CRF 模型
crf = sklearn_crfsuite.CRF(
    algorithm='lbfgs',
    c1=0.1, c2=0.1,
    max_iterations=100,
    all_possible_transitions=True
)
crf.fit(X_train, y_train)

# 评估模型
y_pred = crf.predict(X_test)
print(metrics.flat_classification_report(y_test, y_pred))

# 输出 CRF 模型的特征权重
for (label, label_id) in crf.classes_:
    print(f'{label}: {crf.state_features_[(label_id, "word.lower()")]}')

运行结果
在这里插入图片描述

综合评估:
准确率(Accuracy):
你的模型总体的准确率是 0.61,即模型在所有 371 个样本中,正确分类的比例是 61%。

Macro Average:
这是所有类别的 精确率、召回率 和 F1 值 的简单平均,不考虑类别的样本量。

Precision:0.33
Recall:0.23
F1-score:0.24
这些数值表示,虽然模型在一些标签上表现不错(如 O 标签),但在大部分标签上性能较差,尤其是 B-EDU, B-NAME 等标签的精确率和召回率都为 0。

Weighted Average:
这是考虑类别的样本量后得到的加权平均,给更多样本量大的类别更多权重。

Precision:0.68
Recall:0.61
F1-score:0.58
加权平均数值较高,意味着模型在大样本量类别(如 O 标签)上的表现较好,模型更多地倾向于在这些常见类别上做出正确预测。当然如果我们想更好的预测,还是要使用一些主流的模型,例如BERT-BILSTM-CRF等架构,或者参考下图,一些作者提出的模型,数值都是比较高的了,NLP在进步,NER更在进步,数值在一点点的逼近100%

在这里插入图片描述

🍋6. 总结

条件随机场(CRF)是一种强大的序列建模方法,能够捕捉标签之间的依赖关系。在命名实体识别(NER)任务中,CRF能够通过建模词汇之间的关系,提高模型的性能。结合BERT或LSTM等深度学习模型,CRF在NER任务中的表现更加优秀。通过BERT-CRF和LSTM-CRF的实现,本文展示了如何将CRF与现代深度学习方法结合,从而提升命名实体识别的效果。

在实际应用中,NER模型需要根据具体任务的需求选择合适的框架和特征,例如是否需要考虑长距离依赖、是否有大量上下文信息等。在未来,我们可以进一步探索如何利用更加复杂的模型和特征来优化NER任务的性能。

请添加图片描述

挑战与创造都是很痛苦的,但是很充实。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2244567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qlik Sense QVD 文件

QVD 文件 QVD (QlikView Data) 文件是包含从 Qlik Sense 或 QlikView 中所导出数据的表格的文件。QVD 是本地 Qlik 格式,只能由 Qlik Sense 或 QlikView 写入和读取。当从 Qlik Sense 脚本中读取数据时,该文件格式可提升速度,同时又非常紧凑…

ESP8266 AP模式TCP客户端 电脑手机网络调试助手

1.AP模式TCP客户端和电脑网络调试助手 2.AP模式TCP客户端和手机网络调试助手

Python脚本-linux远程安装某个服务

需求: 某公司因为网站服务经常出现异常,需要你开发一个脚本对服务器上的服务进行监控;检测目标服务器上是否存在nginx软件(提供web服务的软件),如果不存在则安装(服务器可能的操作系统Ubuntu24/RedHat9);如果nginx软件…

linux 中mysql查看慢日志

1、到mysql容器,先登录到数据库,查看是否开启 mysql -h 127.0.0.1 -uroot -p SHOW VARIABLES LIKE slow_query_log; 2、如果没有开启,需要先开启 set global slow_query_log ON; 3、查看慢日志文件 SHOW VARIABLES LIKE slow_query_log…

笔记02----重新思考轻量化视觉Transformer中的局部感知CloFormer(即插即用)

1. 基本信息 论文标题: 《Rethinking Local Perception in Lightweight Vision Transformer》中文标题: 《重新思考轻量化视觉Transformer中的局部感知》作者单位: 清华大学发表时间: 2023论文地址: https://arxiv.org/abs/2303.17803代码地址: https://github.com/qhfan/CloF…

光猫、路由器、交换机之连接使用(Connection and Usage of Optical Cats, Routers, and Switches)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

群核科技首次公开“双核技术引擎”,发布多模态CAD大模型

11月20日,群核科技在杭州举办了第九届酷科技峰会。现场,群核科技首次正式介绍其技术底层核心:基于GPU高性能计算的物理世界模拟器。并对外公开了两大技术引擎:群核启真(渲染)引擎和群核矩阵(CAD…

目录背景缺少vscode右键打开选项

目录背景缺少vscode右键打开选项 1.打开右键管理 下载地址:https://wwyz.lanzoul.com/iZy9G2fl28uj 2.开始搜索框搜索vscode, 找到其源目录 3.目录背景里面, 加入vscode.exe 3.然后在目录背景下, 右键, code就可以打…

【已解决】“EndNote could not connect to the online sync service”问题的解决

本人不止一次在使用EndNote软件时遇到过“EndNote could not connect to the online sync service”这个问题。 过去遇到这个问题都是用这个方法来解决: 这个方法虽然能解决,但工程量太大,每次做完得歇半天身体才能缓过来。 后来再遇到该问…

Java小白成长记(创作笔记一)

目录 序言 思维导图 开发流程 新建SpringBoot并整合MybatisPlus 新建SpringBoot 整合MybatisPlus 统一结果封装 全局异常处理 引入数据库 序言 在一个充满阳光的早晨,一位对编程世界充满好奇的年轻人小小白,怀揣着梦想与激情,踏上了学习…

vue--响应式数据

1、建一个vue应用程序&#xff08;简约&#xff09; 引入外链式 <title>第一个Vue程序</title><script src"../vue.global.js"></script> </head> {{}}插值表达式 <body><!-- {{ }} 插值表达式, 可以将 Vue 实例中定义的…

网络安全,文明上网(2)加强网络安全意识

前言 在当今这个数据驱动的时代&#xff0c;对网络安全保持高度警觉已经成为每个人的基本要求。 网络安全意识&#xff1a;信息时代的必备防御 网络已经成为我们生活中不可或缺的一部分&#xff0c;信息技术的快速进步使得我们对网络的依赖性日益增强。然而&#xff0c;网络安全…

怎么做好白盒测试?

白盒测试 一、什么是白盒测试&#xff1f;二、白盒测试特点三、白盒测试的设计方法1、逻辑覆盖法1、测试设计方法—语句覆盖a、用例设计如下&#xff1a;b、语句覆盖的局限性 2、测试设计方法—判定覆盖a、测试用例如下&#xff1a;b、判定覆盖的局限性 3、测试设计方法—条件覆…

阻尼Newton方法-数值最优化方法-课程学习笔记-5

这篇文章我们继续来学习数值最优化方法第三章的后续内容 阻尼Newton方法 这一章我们以及在之前了解过了&#xff1a;最速下降法&#xff0c;基本Newton方法&#xff0c;这一节我们来了解阻尼newton方法 之前我们提到的基本Newton方法是以一固定步长和Newton方向进行迭代的&a…

力扣 只出现一次的数字-136

只出现一次的数字-136 class Solution { public:int singleNumber(vector<int>& nums) {//按位异或的规则是&#xff1a;两个二进制位相同时结果为0&#xff0c;不同时结果为1//具有自反性&#xff0c;两个二进制位相同时结果为0&#xff0c;一个数(a)和0按位异或的…

Vue.js 自定义指令:从零开始创建自己的指令

vue使用directive 前言vue2使用vue3使用 前言 关于使用自定义指令在官网中是这样描述的 vue2:对普通 DOM 元素进行底层操作&#xff0c;这时候就会用到自定义指令。 vue3:自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。 在 Vue.js 中使用自定义指令&#xf…

MySQL-关键字执行顺序

&#x1f496;简介 在MySQL中&#xff0c;SQL查询语句的执行遵循一定的逻辑顺序&#xff0c;即使这些关键字在SQL语句中的物理排列可能有所不同。 &#x1f31f;语句顺序 (8) SELECT (9) DISTINCT<select_list> (1) FROM <left_table> (3) <join_type> JO…

Odoo :免费且开源的农牧行业ERP管理系统

文 / 开源智造Odoo亚太金牌服务 引言 提供农牧企业数字化、智能化、无人化产品服务及全产业链高度协同的一体化解决方案&#xff0c;提升企业智慧种养、成本领先、产业互联的核心竞争力。 行业典型痛点 一、成本管理粗放&#xff0c;效率低、管控弱 产品研发过程缺少体系化…

labview记录系统所用月数和天数

在做项目时会遇到采集系统的记录&#xff0c;比如一个项目测试要跑很久这个时候就需要在软件系统上显示项目运行了多少天&#xff0c;从开始测试开始一共用了多少年多少月。 年的话还好计算只需要把年份减掉就可以了&#xff0c;相比之下月份和天数就比较难确定&#xff0c;一…

【C++笔记】list使用详解及模拟实现

前言 各位读者朋友们大家好&#xff01;上期我们讲了vector的使用以及底层的模拟实现&#xff0c;这期我们来讲list。 目录 前言一. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.…