hanlp 训练模型_开源自然语言处理工具包hanlp中CRF分词实现详解

f030cd7ee63debea18962967711c9073.png

CRF简介

CRF是序列标注场景中常用的模型,比HMM能利用更多的特征,比MEMM更能抵抗标记偏置的问题。

[gerative-discriminative.png]

CRF训练

这类耗时的任务,还是交给了用C++实现的CRF++。关于CRF++输出的CRF模型,请参考《CRF++模型格式说明》。

CRF解码

解码采用维特比算法实现。并且稍有改进,用中文伪码与白话描述如下:

首先任何字的标签不仅取决于它自己的参数,还取决于前一个字的标签。但是第一个字前面并没有字,何来标签?所以第一个字的处理稍有不同,假设第0个字的标签为X,遍历X计算第一个字的标签,取分数最大的那一个。

如何计算一个字的某个标签的分数呢?某个字根据CRF模型提供的模板生成了一系列特征函数,这些函数的输出值乘以该函数的权值最后求和得出了一个分数。该分数只是“点函数”的得分,还需加上“边函数”的得分。边函数在本分词模型中简化为f(s’,s),其中s’为前一个字的标签,s为当前字的标签。于是该边函数就可以用一个4*4的矩阵描述,相当于HMM中的转移概率。

实现了评分函数后,从第二字开始即可运用维特比后向解码,为所有字打上BEMS标签。

实例

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HanLP是一系列模型与算法组成的NLP工具包,由大快搜索主导并完全开源,目标是普及自然语言处理在生产环境的应用.HanLP具备功能完善,性能高效,架构清晰,语料时新,可自定义的特点。 HanLP提供下列功能: 分词 HMM-两字组(速度与精度最佳平衡;一百兆内存) 最短路分词,N-最短路分词 由字构词(侧重精度,全世界最大语料库,可识别新词;适合NLP任务) 感知机分词CRF分词 词典分词(侧重速度,每秒数千万字符;省内存) 极速词典分词 所有分词器都支持: 索引全切分模式 用户自定义词典 兼容繁体文 训练用户自己的领域模型 词性标注 HMM词性标注(速度快) 感知机词性标注,CRF词性标注(精度高) 命名实体识别 基于HMM角色标注的命名实体识别(速度快) 国人名识别,音译人名识别,日本人名识别,地名识别,实体机构名识别 基于线性模型的命名实体识别(精度高) 感知机命名实体识别,CRF命名实体识别 关键词提取 TextRank关键词提取 自动摘要 TextRank自动摘要 短语提取 基于互信息和左右信息熵的短语提取 拼音转换 多音字,声母,韵母,声调 简繁转换 简繁分歧词(简体,繁体,台湾正体,香港繁体) 文本推荐 语义推荐,拼音推荐,字词推荐 依存句法分析 基于神经网络的高性能依存句法分析器 基于ArcEager转移系统的柱搜索依存句法分析器 文本分类 情感分析 文本聚类 KMeans,Repeated Bisection,自动推断聚类数目k word2vec 词向量训练,加载,词语相似度计算,语义运算,查询,KMEANS聚类 文档语义相似度计算 语料库工具 部分默认模型训练自小型语料库,鼓励用户自行训练。模块所有提供训练接口,语料可参考98年人民日报语料库。 在提供丰富功能的同时,HanLP内部模块坚持低耦合,模型坚持惰性加载,服务坚持静态提供,词典坚持明文发布,使用非常方便。默认模型训练自全世界最大规模的文语料库,同时自带一些语料处理工具,帮助用户训练自己的模型
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
以下是一个简单的BiLSTM-CRF分词的代码实现,使用Python和PyTorch框架: ```python import torch import torch.nn as nn import torch.optim as optim # 定义BiLSTM-CRF模型 class BiLSTM_CRF(nn.Module): def __init__(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim): super(BiLSTM_CRF, self).__init__() self.embedding_dim = embedding_dim self.hidden_dim = hidden_dim self.vocab_size = vocab_size self.tag_to_ix = tag_to_ix self.tagset_size = len(tag_to_ix) # 定义词嵌入层 self.word_embeddings = nn.Embedding(vocab_size, embedding_dim) # 定义双向LSTM层 self.lstm = nn.LSTM(embedding_dim, hidden_dim // 2, num_layers=1, bidirectional=True) # 定义全连接层 self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size) # 定义转移矩阵 self.transitions = nn.Parameter(torch.randn(self.tagset_size, self.tagset_size)) # 定义开始和结束的标记 self.start_tag = torch.tensor([tag_to_ix['<START>']], dtype=torch.long) self.end_tag = torch.tensor([tag_to_ix['<END>']], dtype=torch.long) # 初始化参数 nn.init.xavier_uniform_(self.transitions) def _forward_alg(self, feats): # 初始化alpha值 init_alphas = torch.full((1, self.tagset_size), -10000.) init_alphas[0][self.tag_to_ix['<START>']] = 0. # 转换为张量 forward_var = init_alphas # 迭代每个词的特征 for feat in feats: alphas_t = [] for next_tag in range(self.tagset_size): emit_score = feat[next_tag].view(1, -1).expand(1, self.tagset_size) trans_score = self.transitions[next_tag].view(1, -1) next_tag_var = forward_var + trans_score + emit_score alphas_t.append(self._log_sum_exp(next_tag_var).view(1)) forward_var = torch.cat(alphas_t).view(1, -1) terminal_var = forward_var + self.transitions[self.tag_to_ix['<END>']] alpha = self._log_sum_exp(terminal_var) return alpha def _score_sentence(self, feats, tags): # 计算序列得分 score = torch.zeros(1) tags = torch.cat([self.start_tag, tags]) for i, feat in enumerate(feats): score = score + self.transitions[tags[i + 1], tags[i]] + feat[tags[i + 1]] score = score + self.transitions[self.tag_to_ix['<END>'], tags[-1]] return score def _viterbi_decode(self, feats): backpointers = [] # 初始化viterbi变量 init_vvars = torch.full((1, self.tagset_size), -10000.) init_vvars[0][self.tag_to_ix['<START>']] = 0 # 迭代每个词的特征 forward_var = init_vvars for feat in feats: bptrs_t = [] viterbivars_t = [] for next_tag in range(self.tagset_size): next_tag_var = forward_var + self.transitions[next_tag] best_tag_id = self._argmax(next_tag_var) bptrs_t.append(best_tag_id) viterbivars_t.append(next_tag_var[0][best_tag_id].view(1)) forward_var = (torch.cat(viterbivars_t) + feat).view(1, -1) backpointers.append(bptrs_t) # 最后添加结束标记 terminal_var = forward_var + self.transitions[self.tag_to_ix['<END>']] best_tag_id = self._argmax(terminal_var) path_score = terminal_var[0][best_tag_id] # 回溯路径 best_path = [best_tag_id] for bptrs_t in reversed(backpointers): best_tag_id = bptrs_t[best_tag_id] best_path.append(best_tag_id) start = best_path.pop() assert start == self.tag_to_ix['<START>'] best_path.reverse() return path_score, best_path def _log_sum_exp(self, vec): # 计算log-sum-exp max_score = vec[0, self._argmax(vec)] max_score_broadcast = max_score.view(1, -1).expand(1, vec.size()[1]) return max_score + torch.log(torch.sum(torch.exp(vec - max_score_broadcast))) def _argmax(self, vec): # 返回最大值的下标 _, idx = torch.max(vec, 1) return idx.item() def neg_log_likelihood(self, sentence, tags): # 计算负对数似然损失 self.hidden = self.init_hidden() embeds = self.word_embeddings(sentence) lstm_out, _ = self.lstm(embeds.view(len(sentence), 1, -1)) lstm_out = lstm_out.view(len(sentence), self.hidden_dim) lstm_feats = self.hidden2tag(lstm_out) forward_score = self._forward_alg(lstm_feats) gold_score = self._score_sentence(lstm_feats, tags) return forward_score - gold_score def forward(self, sentence): # 预测标签 self.hidden = self.init_hidden() embeds = self.word_embeddings(sentence) lstm_out, _ = self.lstm(embeds.view(len(sentence), 1, -1)) lstm_out = lstm_out.view(len(sentence), self.hidden_dim) lstm_feats = self.hidden2tag(lstm_out) score, tag_seq = self._viterbi_decode(lstm_feats) return score, tag_seq def init_hidden(self): # 初始化LSTM隐藏层 return (torch.randn(2, 1, self.hidden_dim // 2), torch.randn(2, 1, self.hidden_dim // 2)) # 定义标签和词汇表 START_TAG = "<START>" END_TAG = "<END>" tag_to_ix = {START_TAG: 0, "B": 1, "I": 2, "O": 3, END_TAG: 4} ix_to_tag = {v: k for k, v in tag_to_ix.items()} vocab_size = len(word_to_ix) # 定义模型和优化器 model = BiLSTM_CRF(vocab_size, tag_to_ix, EMBEDDING_DIM, HIDDEN_DIM) optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4) # 训练模型 for epoch in range(300): for sentence, tags in training_data: # 清空梯度 model.zero_grad() # 转换为张量 sentence_in = prepare_sequence(sentence, word_to_ix) targets = torch.tensor([tag_to_ix[t] for t in tags], dtype=torch.long) # 计算损失函数并更新模型 loss = model.neg_log_likelihood(sentence_in, targets) loss.backward() optimizer.step() # 测试模型 with torch.no_grad(): precheck_sent = prepare_sequence(test_data[0][0], word_to_ix) print(model(precheck_sent)) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值